Spring支持的Quartz程序调度

开发时有时会有这样一种需求,定期计算某些数据或者执行某些程序进行操作,这种程序就是平时所说的批处理。批处理为应用分时段处理提供支持,减轻应用程序的负担,比如数据统计工作往往放在凌晨执行,这是服务器压力不大,使用者不多,是进行此类操作的最佳时段。白天人们使用时就能看到处理的结果了。
批处理程序的执行思路是先创建执行定时任务,然后对定时任务进行调度执行。
Java中的Timer类为批处理程序运行提供支持,要求扩展java.util.Timer类。Spring也支持Timer方式的调度,但是用过Quartz之后还是感觉Quartz更顺手,扩展性更强。但Quartz使用的定时方式是CRON表达式,这部分内容网上也很多,难度不大。
先搭建一个开发环境,很简单。运用了Java EE的分层结构,但测试时只是单机运行,下面我们一一来看。
[img]http://dl.iteye.com/upload/attachment/304032/c8bd7641-854b-3c32-afe1-0d3a1bbb96a4.jpg[/img]
我们在Sercice类中定义业务操作的基本方法,比如数据库操作,计算等,这里是我们具体执行业务逻辑的地方,为了说明问题,就打印一句话,如下:
package org.ourpioneer.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* 调度程序业务处理类
*
* @author Sarin
*
*/
public class QuartzService {
private static final Logger logger = LoggerFactory
.getLogger(QuartzService.class);

public QuartzService() {
logger.debug("Construct QuartzService");
}

public void insertIntoDB() {
logger.debug("Run Insert Method");
}
}

为了结合Spring展示实例化类和方法调用顺序,这里在构造方法中也打印log。业务类很简单,定义操作的方法就行了。
调用Service的类是Job类,就是调度程序调度的类,每个调度称为一个Job,很形象,我们来看看:
package org.ourpioneer.quartz.job;

import org.ourpioneer.service.QuartzService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* 调度任务
*
* @author Sarin
*
*/
public class QuartzJob {
private static final Logger logger = LoggerFactory
.getLogger(QuartzJob.class);
// 业务类注入
private QuartzService quartzService;

public void setQuartzService(QuartzService quartzService) {
this.quartzService = quartzService;
logger.debug("QuartzService Injection");
}

public QuartzJob() {
logger.debug("Construct QuartzJob");
}

/**
* 目标执行方法
*/
public void execute() {
// 调度执行程序
quartzService.insertIntoDB();
logger.debug("Run QuartzJob");
}
}

Job类可以是一个简单的POJO,方法名都是随意定的,它们都是可以在Spring中配置的,Job类调用了Service类的业务方法,那么要将Service类注入。而Job类要被调度程序调度运行。
要运行调度程序,就要在Spring容器中实例化调度程序,这在Java EE程序运行时,因为容器是时时运行的,只要加载了响应的配置文件即可,而我们单机测试,要手工启动程序,启动Spring的方法很简单:
package org.ourpioneer.quartz.app;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
* 任务调度测试类
*
* @author Sarin
*
*/
public class QuartzApp {
private static final Logger logger = LoggerFactory
.getLogger(QuartzApp.class);

public QuartzApp() {
logger.debug("Construct QuartzApp");
}

public static void main(String[] args) {
new ClassPathXmlApplicationContext("classpath:spring/quartz.xml");
logger.debug("Run QuartzApp");
}
}

使用类路径下的XML加载方式,找到配置文件quartz.xml,来启动Spring容器。下面就剩下Spring的配置了,我们逐条来看:
<!-- Service配置 -->
<bean id="quartzService"
class="org.ourpioneer.service.QuartzService"></bean>

我们将Service放到Spring容器中,它会随着Spring容器加载而实例化,实现控制反转。下面是调度Job的定义:

<!-- 定义调度对象和调用的方法 -->
<bean id="quartzJob"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<bean class="org.ourpioneer.quartz.job.QuartzJob">
<property name="quartzService" ref="quartzService" />
</bean>
</property>
<property name="targetMethod">
<value>execute</value>
</property>
</bean>

调度对象是targetObject,在其中注入我们自定义的Job,而Job依赖quartzService,那么不能忘记注入它。下面是targetMethod设置,就是调度的方法名,前面写的是execute,这里一样。所以这就体现了配置的灵活性。
调度程序有了,那么要定时执行,怎么来告诉控制程序来执行呢?监听时间,没错,这里使用的就是这种机制,不过不是监听器,监听器是监听事件的发生,而不能监听时间的到达,这里就是触发器,但和数据库的触发器不同,数据库的触发器还是监听了数据操作的事件,而不是时间。定点触发调度程序,要配置触发器:

<!-- 配置触发器 -->
<bean id="QuartzCornTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref local="quartzJob" />
</property>
<!-- 触发时间(使用cron表达式) -->
<property name="cronExpression">
<value>0/5 * * * * ?</value>
</property>
</bean>

触发器中注入了调度的Job,就是我们上面定义的quartzJob,接着设置了触发的时间,使用了CRON表达式,下面简单说说CRON表达式。
CRON表达式使用7个域来表示时间,以空格分隔开,最后一个域是年,这个是可选的,示例中就没有。剩下的六个域依次是秒,分,小时,每月的几号,月份,一周中的周几。*号表示通配符,匹配所有值。?号也是通配符,但是只能匹配每月的几号和一周的周几,而且这两个不能同时匹配。/表示增量,就是每隔多少触发一次。每个域可以是固定数值,也可以是范围(如1-5)或一个列表(如1,3,5),好了,就这么简单。示例中的含义就是从0秒开始每隔5秒执行一次,而分,小时等都是随意的,所以它会在0,5,10,15…这样的秒数时执行。要配置每天凌晨4点执行的触发器就是0 0 4 * * ?了。
Spring的配置就结束了,非常简单,我们来看一下bean的关系图,更直观一点:
[img]http://dl.iteye.com/upload/attachment/304034/3744154a-059c-36df-a5b1-d815bffaf9f5.jpg[/img]
这里就看出了它们之间的依赖关系,下面我们来测试,启动主函数运行:
[img]http://dl.iteye.com/upload/attachment/304036/6c68da35-bd4c-3f3d-9d59-b9dc2ade3389.jpg[/img]
本文系作者的实践探索,希望对使用者有用,欢迎交流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值