spring定时任务

参考资料:Spring Framework Reference Documentation 3.2.4.RELEASE的Part VI. Integration的27. Task Execution and Scheduling

前话:系统自带定时任务与spring定时任务.

spring定时任务好处:1.跨平台,不用理会是windows还是linux. 2.在应用上实现功能而不是在系统上直接实现,不用受操作系统运维人员限制.

如果应用崩溃,spring定时任务也会跟着宕掉,想搞死操作系统的定时任务没那么容易.这点是好是坏,说不定.或许你希望应用死,任务也跟着死;或许你希望应用死了,任务还要执行.


下面介绍基于xml和java-config的两种配置使用方法.
一.基于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


你可能感兴趣的:(spring,schedule,定时任务)