Spring学习:使用Spring调度任务
原文出处:http://blog.youkuaiyun.com/CMTobby/article/details/1795257
并非应用系统中发生的所有事情都是由用户的动作引起的。有时候,系统自己也会发起一个动作。比方说最近的项目中,要求系统每到晚上12点就检查数据库中所有订单的状态,将所有草稿状态的订单的状态修改为超时取消。这个时候我们就可以利用Spring为我们提供的任务调度功能了。
今天自己试用了一把Spring的任务调度,我的逻辑很简单,让后台每过一分钟就打印一句“This is My Schedule Test”。下面开始吧!
一.创建一个工作类
首先我们要创建一个类来定义工作。要做到这点,我们需要从Spring的QuartzJobBean中派生子类,如下所示:
QuartzJobBean.java:
import org.springframework.scheduling.quartz.QuartzJobBean;
import test.service.IScheduleDetail;
/**
*@authorCMTobby2007-9-21
*/
publicclass PrintMessageJob extends QuartzJobBean {
private IScheduleDetail scheduleDetail;
private String msg;
@Override
protectedvoid executeInternal(JobExecutionContext arg0) throws JobExecutionException {
scheduleDetail.printDetail();
}
public IScheduleDetail getScheduleDetail() {
returnscheduleDetail;
}
publicvoid setScheduleDetail(IScheduleDetail scheduleDetail) {
this.scheduleDetail = scheduleDetail;
}
}
这里我们还需要下载一个Quartz的包,最新的是quartz-1.6.0.jar
尽管这个任务掉多执行的操作很简单,但是为了体现分层思想,我还是将这个操作写在了service层中。代码如下所示:
IScheduleDetail.java:
package test.service;
publicinterface IScheduleDetail {
publicvoid printDetail();
}
ScheduleDetailImpl.java:
package test.service.impl;
import test.service.IScheduleDetail;
/**
*@authorzhukai2007-9-21
*
*/
publicclass ScheduleDetailImpl implements IScheduleDetail {
publicvoid printDetail() {
System.out.println("这个是我们要调度的动作");
}
}
这样的话我们只需在工作类中简单的调用服务类即可,工作类只负责被调度时调用具体的方法,在服务类中我们还可以扩展别的操作。注意,executeInternal方法继承自QuartzJobBean,我们必须实现它,当任务被调度的时候就是执行这个方法。
二.让Spring知道你的工作类
工作类定义好了如何让Spring知道呢?我们只需要在Spring中配置文件中声明即可,如下所示:
<!—- 配置服务 -->
<bean id="scheduleDetail"
class="test.service.impl.ScheduleDetailImpl">
</bean>
<!-- 创建一个工作 -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<!-- 指定要调度的工作,需实现Job接口,通常是继承QuartzJobBean抽象类 -->
<property name="jobClass">
<value>test.web.PrintMessageJob</value>
</property>
<property name="jobDataAsMap">
<map>
<entry key="scheduleDetail">
<ref bean="scheduleDetail"/>
</entry>
</map>
</property>
</bean>
这里我们使用了JobDetailBean类,它的jobClass用于指定工作类,这里类通常要实现org.quartz.Job接口。jobDataAsMap属性用来给jobClass所指定类的属性注入值,例如上例中我们给PrintMessageJob的scheduleDetail属性注入了一个已声明好的bean。
三.调度工作
现在我们需要来对工作进行调度了,譬如说指定何时开始以怎样的频率来执行这个任务。本例中我们是指定每分钟打印一条语句。我们的调度配置如下所示:
<!-- 调度一个工作 -->
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail">
<ref bean="jobDetail"/>
</property>
<!-- 工作执行的频率,以毫秒为单位 -->
<property name="repeatInterval">
<value>60000</value><!—- 一分钟打印一次 -->
</property>
</bean>
四.启动工作
一切准备就绪之后,我们就要启动我们的工作调度任务了,配置如下:
<!-- 启动工作 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers"><!-- 接受一组触发器 -->
<list>
<ref bean="simpleTrigger"/>
</list>
</property>
</bean>
OK,现在我们服务器(我的Spring是和Struts集成在一起的),就会发现每过一分钟,后台就会打印出一句:这个是我们要调度的动作,是不是很简单。
最后有一点要说明的,这个问题浪费了很多时间:我在启动服务的时候总是提示我不能创建名字为 jobDetail 的bean,然后提示 NoSuchMethodError 错误,如下所示: org.apache.commons.collections.SetUtils.orderedSet(Ljava/util/Set;) 为此我检查了我的配置和程序不下几十次,还上网找了很多资料,最后导致这个错误的原因很简单:我用的commons-collections-2.1.1.jar包太老了,我下载最新的commons-collections-3.2.jar包放进去之后就一切OK了,这个错误BT吧。