前话:系统自带定时任务与spring定时任务.
spring定时任务好处:1.跨平台,不用理会是windows还是linux. 2.在应用上实现功能而不是在系统上直接实现,不用受操作系统运维人员限制.
如果应用崩溃,spring定时任务也会跟着宕掉,想搞死操作系统的定时任务没那么容易.这点是好是坏,说不定.或许你希望应用死,任务也跟着死;或许你希望应用死了,任务还要执行.
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)); }