Spring本身不提供任务调度的直接实现,但是Spring在自身框架原则前提下提供了对Timer和Quartz的集成。使用spring容器可以轻松地对既有的bean进行任务调度。
在说明如何在spring中使用任务调度之前,首先来看看Timer本身。
JDK中提供的Timer是比Quartz更为简单的调度方法,当然,Quartz提供了更为强大的功能。相比Timer,Quartz独有的特性包括:
1、支持持久性作业。Quartz允许将作业状态持久化,在应用服务器重启之间,也能够保持一致的作业状态。
2、类Cron的定时支持。通过Quartz的CronTrigger,Quartz允许使用类似Unix调度的方式来制定作业何时执行。而Timer只允许执行时间和间隔的规范。
3、线程处理模型。Timer是使用单线程实现作业,而Quartz使用线程池来执行作业。线程池的大小以及实现都可以用Quartz属性来制定。
4、提供成熟的事件模型,用于监控调度系统的各个方面包括调度器,触发器和作业。
5、另外Quartz还提供了哑火指令用于指定当任务没有正常激活该做什么。提供了插件支持,提供了servlet用以初始化。
Spring提供了一致的方式来支持这两种调度机制。
1)首先来看Timer,在spring中使用Timer与使用原生态的Timer有所不同,在spring最简单的方法就是使用MethodInvokingTimerTaskFactoryBean方法来创建任务,配置如下
<bean id="methodInvokingTask" class="org.springframework.scheduling.timer.MethodI/nvokingTimerTaskFactoryBean">
<property name="targetObject"> <ref bean="exampleBusinessObject"/></property>
<property name="targetMethod"> <value>doSomething</value></property>
</bean>
以上的配置就会创建一个TimerTask,调用exampleBusinessObject的idoSomething。
接下来需要配置的是该timerTask的调度策略:
<bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="delay">
<value>60000</value>
</property>
<property name="period">
<value>60000</value>
</property>
<property name="timerTask">
<ref bean="methodInvokingTask"/>
</property>
</bean>
以上两个配置指定了要运行什么任务,何时运行,现在还需要预定这些任务:
<bean id="timerFactory" class="org.spring.framework.Scheduling.timer.TimerFactoryBean">
<property name="ScheduledTimerTask">
<list>
<ref local="ScheduledTask"/>
</list>
</property>
</bean>
TimerFactoryBean允许多个ScheduledTask,它会创建和管理Timer实例。
我们除了使用methodInvokingTask这种非侵入方式的TimeTask而外,我们还可以使用自己定义的TimerTask。
Package org.springframework.prospring.scheduling;
public class CustomTask extends TimerTask{
public void run(){// do something}
}
然后直接以spring bean方式配置,替换methodInvokingTask。
2)然后来看看使用Quartz对上述任务的配置。
<bean id="methodInvokingJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"> <ref bean="exampleBusinessObject"/></property>
<property name="targetMethod"> <value>doSomething</value></property>
</bean>
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="startDelay"><value>6000</value></property>
<property name="repeatInterval"><value>6000</value></property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list><ref local="simpleTrigger"/></list>
</property>
</bean>
在Timer中只有两个概念TimerTask和Timer,至于调度细节是通过重载Timer的schedule方法来制定,只是在spring集成中spring将其分解成为了三个步骤。而Quartz确有四个概念,Scheduler(调度器)Trigger(触发器)Job(任务)JobDetail(工作细节),接下来详细来看这四个元素,以及spring对它们的支持:
job
job是具体任务的实现,需要继承自QuartzJobBean并在executeInternal方法中实现具体的任务细节。该方法接受一个参数,JobExcutionContext,其中包含了几乎所有信息的引用,以及需要存放的数据,以供在作业执行之间传递信息。实例代码如下:
package org.springframework.prospring.scheduling;
public class ExampleJob extends QuartzJobBean{
private long lastExecutionDate;
public void setListExecutionDate(long lastExecutionDate){
this.lastExecutionDate = lastExecutionDate;
}
protected void executeInternal(JobExcutionContext context){
//do some thing
// read or write data
JobDataMap map = context,getJobDetail().getJobDataMap();
map.put(”lastExecutionDate",System.currentTimeMills());
}
}
该类的初始化时在Quartz中进行的,需要首先包裹在JobDetail中,JobDetail中负责持有当前任务的相关默认数据。配置如下
<bean id="exampleJobBean" class="org.springframework.quartz.JobDetailBean">
<property name="name"><value>example</value>
<property name="group"><value>examples</value>
......
<property name="jobClass">
<value>org.springframework.prospring.scheduling.ExampleJob</value>
</property>
<bean>
触发器,触发器中描述了作业的触发策略。之前的例子中已经提到一种方式,其实Quartz提供了两种方式触发器,simple和cron。cron使用类似于Unix中的调度描述表达式,配置如下:
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="exampleJobDetail"/>
</property>
<property name="cronExpression">
<value>0 15 4 ? * MON-FRI</value>
</property>
<bean>
触发器中还可以指定哑火指令,指定监听器。
调度器,作为Quartz系统的主要部分,它维护了所有的作业细节和关联触发器的一个注册项;它在作业被激活的时候,它管理作业的创建和运行,并且负责保持作业的状态信息。