前话:系统自带定时任务与spring定时任务.
spring定时任务好处:1.跨平台,不用理会是windows还是linux. 2.在应用上实现功能而不是在系统上直接实现,不用受操作系统运维人员限制.
如果应用崩溃,spring定时任务也会跟着宕掉,想搞死操作系统的定时任务没那么容易.这点是好是坏,说不定.或许你希望应用死,任务也跟着死;或许你希望应用死了,任务还要执行.
一.基于xml
1.先写一个普通类,这个类包括一个方法.将这个类注册成bean.
@Component
public class TimerTask {
public void executeTask(){
System.out.println(new Date());
}
}
2.在spring容器定义一个task:scheduler,再定义一个task:scheduled-tasks,其中task:scheduled-tasks会引用task:scheduler.task:scheduled-tasks的一个子元素就可以看成一个任务,它可以是普通执行任务,也可以是我们要使用的定时任务.比如我们这里指定是那个bean的那个方法,执行的时间.
<task:scheduled-tasks scheduler="myScheduler">
<task:scheduled ref="timerTask" method="executeTask" cron="0 0/1 * * * *"/>
</task:scheduled-tasks>
<task:scheduler id="myScheduler" pool-size="10"/>
3.测试.
public static void main(String[] args) {
new ClassPathXmlApplicationContext("applicationContext.xml");
}
还可以启动jetty,作为servlet容器,只要不关闭jetty,spring的容器的生命不会结束
顺便写了个单例模式:
public class TimerTaskTest {
ApplicationContext context=null;
private static TimerTaskTest timerTaskTest = null;
public static TimerTaskTest getInstance() {
if (timerTaskTest == null) {
timerTaskTest = new TimerTaskTest();
}
return timerTaskTest;
}
private TimerTaskTest() {
context=new ClassPathXmlApplicationContext("applicationContext.xml");
}
public Object getBean(String name){
return context.getBean(name);
}
public static void main(String[] args) {
TimerTaskTest.getInstance();
}
}
二.基于java-config
1.与xml类似,先定义一个普通bean,在这个bean的方法上使用@Scheduled注解.代码如下:
@Component
public class TimerTask {
@Scheduled(cron="0 0/1 * * * *")
public void executeTask(){
System.out.println(new Date());
}
}
2.在spring的Configuraion类,使用@EnableScheduling注解启用计划功能,也可以注册一个ScheduledAnnotationBeanPostProcessor Bean来代替这个注解.
3,测试.
public class TimerTaskTest {
public static void main(String[] args) {
new AnnotationConfigApplicationContext(AppConfig.class);
}
}
类似xml.还是启动jetty测试吧
另:这里要理解一下spring容器的生命周期,平时我们使用的spring容器是这样的,先加载bean,然后再对这些bean进行实例化,程序完成,spring的生命周期也就结束了.使用了spring定时任务之后,发现会注册一个listener.xml方式配置的spring:调用org.springframework.scheduling.config.ContextLifecycleScheduledTaskRegistrar的onApplicationEvent方法之后,再去调会父类ScheduledTaskRegistrar的scheduleTasks方法.java-config方式配置的spring:调用org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor的onApplicationEvent方法之后,再调用实例变量ScheduledTaskRegistrar的afterPropertiesSet方法再调用scheduleTasks方法,里面使用了JDK的ScheduledExecutorService去调用这些定时任务,这些调用从而引起线程阻塞,spring容器的生命周期也就没结束.(使用单元测试发现不起作用,我估计使用了单元测试的多个线程,并没有引起线程阻塞,spring容器的生命周期也就结束了),下面是一个超简单例子,此例并没有将CronTaskBean注册成spring的bean.
public static void main(String[] args) throws Exception {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
ContextLifecycleScheduledTaskRegistrar registrar=new ContextLifecycleScheduledTaskRegistrar();
registrar.setApplicationContext(context);
registrar.addCronTask(new ScheduledMethodRunnable(new CronTaskBean(),"executeTask"),"0/5 * * * * *");
registrar.onApplicationEvent(new ContextRefreshedEvent(context));
}
0 0/1 * * * *的意思是当TimerTask bean实例化开始,executeTask方法成为一个task开始算起,刚好是每分钟的0分开始执行任务.比如:23点52分18秒就成为一个task,那么触发executeTask方法是23点53分0秒,23点54分0秒...
源码:http://download.csdn.net/detail/xiejx618/7689063