写随笔主要是当做日记,方便以后查看,遇到该问题时获取解决方法。
Spring3.0后就自带了定时任务功能,接下来记录 Spring如何配置定时器,定时器运行流程。
一、Spring配置定时器,开启定时调度功能。
javaWeb 工程得先集成Spring框架,集成后在applicationcontext.xml文件同级目录下新建一个quartz_config.xml文件,工程目录如下:
quartz_config.xml代码如下(配置Spring定时任务所需信息,如果applicationcontext.xml文件中已经引入则不需要在配置该文件。):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<task:annotation-driven></task:annotation-driven>
</beans>
二、创建定时执行方法。
后台创建一个MyTestJob.java类,创建一个定时执行的方法executeCalcReconFileData。
package com.tscp.base.job;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.tscp.base.utils.spring.DateUtils;
/**
* 定时器测试类
*
* @author yangmin
* @since 1.0
* @version 2017-11-18 yangmin
*/
@Component
public class MyTestJob {
/**
* 执行定时统计对账结果
*/
@Scheduled(cron = "0/5 * * * * ?")
public void executeCalcReconFileData() {
String strNowTime = DateUtils.getTime();
System.out.println("\n执行定时器,执行时间:" + strNowTime);
}
}
这里对方法使用Spring的Scheduled注解,配置定时器每五秒钟调用一次executeCalcReconFileData方法,cron表达式参考: http://rainbowdesert.iteye.com/blog/2107220。
程序运行结果:
三、通过配置文件获取定时器执行时间。
1、创建配置文件项目启动时将配置信息读取到容器中。
在config目录下创建一个quart_config.properties文件,用来配置定时器信息。在里面配置一个 job.test.taskTimeout=0/10 * * * * ? 的配置信息,既每10秒中执行一次。
#测试定时器
job.test.taskTimeout = 0/10 * * * * ?
2、项目启动加载配置到容器。
在后台创建一个PropertyPlaceholder类,继承PropertyPlaceholderConfigurer类。
package com.tscp.base.utils.spring;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
/**
* 获取配置文件类
*
* @author yangmin
* @since 1.0
* @version 2017-11-18 yangmin
*/
public class PropertyPlaceholder extends PropertyPlaceholderConfigurer {
/** 配置信息存在内存中 */
private static Map<String, String> propertyMap;
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
super.processProperties(beanFactoryToProcess, props);
propertyMap = new HashMap<String, String>();
for (Object key : props.keySet()) {
String keyStr = key.toString();
String value = props.getProperty(keyStr);
propertyMap.put(keyStr, value);
}
}
/**
* 获得内存的配置信息
*
* @param name 配置项名称
* @return String 配置的对象
*/
public static String getProperty(String name) {
return propertyMap.get(name);
}
}
在applicationcontext.xml中配置项目启动加载PropertyPlaceholder的代码,配置在quartz_config.xml文件前,我的applicationcontext.xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- spring集成,注释掉 -->
<context:component-scan base-package="com.tscp" />
<!-- 将多个配置文件读取到容器中,交给Spring管理 -->
<bean id="propertyConfigurer"
class="com.tscp.base.utils.spring.PropertyPlaceholder">
<property name="locations">
<list>
<value>/WEB-INF/config/*_config.properties</value>
</list>
</property>
</bean>
<import resource="quartz_config.xml" />
</beans>
这样项目每次启动时就会把quart_config.properties文件中的信息加载到容器中。
3、后台定时方法修改。
MyTestJob.executeCalcReconFileData方法之前是直接配置cron参数,现在直接去容器中的信息。
@Component
public class MyTestJob {
/**
* 执行定时统计对账结果
*/
//@Scheduled(cron = "0/5 * * * * ?")
@Scheduled(cron = "${job.test.taskTimeout}")
public void executeCalcReconFileData() {
String strNowTime = DateUtils.getTime();
System.out.println("\n执行定时器,执行时间:" + strNowTime);
}
}
现在的cron取额是quart_config.properties文件中的信息,启动项目定时器为每十秒钟执行一次。
三、定时器动态修改cron。
动态修改cron,需要修改定时器执行方法,新建一个UpdateJobTask.java类并实现SchedulingConfigurer接口:
package com.tscp.base.job;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
/**
* 修改定时器任务执行时间
*
*
* @author yangmin
* @since 1.0
* @version 2017-11-21 yangmin
*/
@Component(value = "updateJobTask")
@EnableScheduling
public class UpdateJobTask implements SchedulingConfigurer {
/** FIXME */
public static String cron = "0/5 * * * * ?";
/** FIXME */
public static ScheduledTaskRegistrar taskRegistrar;
/** FIXME */
int i = 0;
/**
* 修改执行时间
*
* @param cronExpression 表达式
* @return 修改结果
*/
public boolean setCron(String cronExpression) {
UpdateJobTask.cron = cronExpression;
return true;
}
/**
* @param taskRegistrar ScheduledTaskRegistrar
* @see org.springframework.scheduling.annotation.SchedulingConfigurer#configureTasks(org.springframework.scheduling.config.ScheduledTaskRegistrar)
*/
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// taskRegistrar.setTaskScheduler(poolScheduler());
taskRegistrar.addTriggerTask(new Runnable() {
@Override
public void run() {
i++;
// 任务逻辑
System.out.println("第" + (i) + "次任务逻辑开始执行操作... " + "时间:【" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(new Date()) + "】");
}
}, new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
// 任务触发,可修改任务的执行周期
CronTrigger trigger = new CronTrigger(cron);
Date nextExec = trigger.nextExecutionTime(triggerContext);
System.out.println("第" + (i) + "次任务触发执行操作... " + "时间:【" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS").format(nextExec) + "】");
return nextExec;
}
});
}
}
定时方法configureTasks在项目启动时会被调用,Trigger一个多少时间之后执行的定时任务,在定时任务run后,会再去Trigger,依次循环。创建一个setCron方法用于改变cron参数,执行结果如下:
nextExecutionTime方法是从i=o开始执行,run从i=1开始执行,在第四次nextExecutionTime后执行了setCron方法,将cron改为10秒执行一次,而任务会在下一次run方法后才使用新的cron,也就是不会立即执行,如需立即执行,则使用Quartz。
javaWeb项目中经常会使用动态定时器,做一下倒计时之类的事务,下篇记录。
ps:好东西值得记录。