Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行。
因为它不能在指定时间执行, 仅仅能让程序依照某一个频度执行,所以TimerTask在实际项目中用的不多。
这里只列一个简单的示例,说明一下Timer的使用方式,不作深入探讨:
需要: spring.jar, commons-logging.jar 两个包
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="taskService" class="com.zdp.service.TaskService">bean>
<bean id="scheduledTimerTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask" ref="taskService" />
<property name="period" value="1000" />
<property name="delay" value="4000" />
bean>
<bean id="timerFactoryBean" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref bean="scheduledTimerTask" />
list>
property>
bean>
beans>
实现方式就是继承TimerTask 类,重写run方法即可。
/**
* 定时调度业务类
*/
public class TaskService extends TimerTask {
@Override
public void run() {
String currentTime = new SimpleDateFormat("yyy-MM-dd hh:mm:ss").format(new Date());
System.out.println(currentTime + " 定时任务正在运行...");
}
}
Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。它的好处是,不需要额外引入jar包,配置比较简单,而且功能也比较全面。
Quartz是一个功能强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,但是配置起来稍显复杂。
在applicationContext.xml中作如下配置
a)配置组件扫描
<context:component-scan base-package="com.xxx.yyy.schedule">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>
b)开启task任务注解扫描
<task:annotation-driven/>
成功添加此配置后,applicationContext.xml的命名空间,会添加以下三项内容
xmlns:task="http://www.springframework.org/schema/task
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd
如上是最简单的配置,可以满足基础的定时任务需求。
在包com.xxx.yyy.schedule下新建定时任务类
@Component
public class WecomMarkTagExecutor {
private Logger logger = LoggerFactory.getLogger(WecomMarkTagExecutor.class);
@Autowired
private WeComMarkTagService weComMarkTagService;
@Scheduled(cron = "0 0/2 * * * ? ")
public void task01() {
try {
logger.info("wecom打标签任务-start");
weComMarkTagService.wecomMarkTag();
logger.info("wecom打标签任务-end");
} catch (Exception e) {
e.printStackTrace();
}
}
}
添加包含的比较简单,就像2)中示例的配置一样。
有时候,定时任务实现类下有些类我们不想放入容器的类,这里放一个通过正则表达式不把指定类放入容器的配置,假设schedule包下有两个定时任务:EveryDayExecutor和WecomMarkTagExecutor,其EveryDayExecutor是其他模块的定时任务,当前模块不能将它放入容器,我们可以作如下配置
<context:component-scan base-package="com.haoys.bdp.*">
<context:exclude-filter type="regex" expression="com.xxx.yyy.schedule.EveryDayExecutor"/>
</context:component-scan>
这个配置的意思是,扫满schedule包下的组件(放入容器),但排除EveryDayExecutor。
corn表达式网上很多讲解,一定要注意检查自己写的对不对;我就是由于corn写错了、导致定时任务不能按预想的执行,以为配置错误,改来改去也改不好,不仅浪费时间、还特别影响心情。
注意cron = "0 0/2 * * * ? ",才是每隔2分钟执行一次;
cron = "0 2 * * * ? ",意思是每个小时的第二分钟执行!
必须开启task注解扫描
,才能使@Scheduled注解被扫到,才能让定时任务生效。