Spring支持Quartz程序调度

开发时有时会有这样一种需求,定期计算某些数据或者执行某些程序进行操作,这种程序就是平时所说的批处理。批处理为应用分时段处理提供支持,减轻应用程序的负担,比如数据统计工作往往放在凌晨执行,这是服务器压力不大,使用者不多,是进行此类操作的最佳时段。白天人们使用时就能看到处理的结果了。
批处理程序的执行思路是先创建执行定时任务,然后对定时任务进行调度执行。
Java中的Timer类为批处理程序运行提供支持,要求扩展java.util.Timer类。Spring也支持Timer方式的调度,但是用过 Quartz之后还是感觉Quartz更顺手,扩展性更强。但Quartz使用的定时方式是CRON表达式,这部分内容网上也很多,难度不大。
先搭建一个开发环境,很简单。运用了Java EE的分层结构,但测试时只是单机运行,下面我们一一来看。

我们在Sercice类中定义业务操作的基本方法,比如数据库操作,计算等,这里是我们具体执行业务逻辑的地方,为了说明问题,就打印一句话,如下:
Java代码

1. package org.ourpioneer.service;
2.
3. import org.slf4j.Logger;
4. import org.slf4j.LoggerFactory;
5.
6. /**
7. * 调度程序业务处理类
8. *
9. * @author Sarin
10. *
11. */
12. public class QuartzService {
13. private static final Logger logger = LoggerFactory
14. .getLogger(QuartzService.class);
15.
16. public QuartzService() {
17. logger.debug("Construct QuartzService");
18. }
19.
20. public void insertIntoDB() {
21. logger.debug("Run Insert Method");
22. }
23. }

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,很形象,我们来看看:
Java代码

1. package org.ourpioneer.quartz.job;
2.
3. import org.ourpioneer.service.QuartzService;
4. import org.slf4j.Logger;
5. import org.slf4j.LoggerFactory;
6.
7. /**
8. * 调度任务
9. *
10. * @author Sarin
11. *
12. */
13. public class QuartzJob {
14. private static final Logger logger = LoggerFactory
15. .getLogger(QuartzJob.class);
16. // 业务类注入
17. private QuartzService quartzService;
18.
19. public void setQuartzService(QuartzService quartzService) {
20. this.quartzService = quartzService;
21. logger.debug("QuartzService Injection");
22. }
23.
24. public QuartzJob() {
25. logger.debug("Construct QuartzJob");
26. }
27.
28. /**
29. * 目标执行方法
30. */
31. public void execute() {
32. // 调度执行程序
33. quartzService.insertIntoDB();
34. logger.debug("Run QuartzJob");
35. }
36. }

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的方法很简单:
Java代码

1. package org.ourpioneer.quartz.app;
2.
3. import org.slf4j.Logger;
4. import org.slf4j.LoggerFactory;
5. import org.springframework.context.support.ClassPathXmlApplicationContext;
6.
7. /**
8. * 任务调度测试类
9. *
10. * @author Sarin
11. *
12. */
13. public class QuartzApp {
14. private static final Logger logger = LoggerFactory
15. .getLogger(QuartzApp.class);
16.
17. public QuartzApp() {
18. logger.debug("Construct QuartzApp");
19. }
20.
21. public static void main(String[] args) {
22. new ClassPathXmlApplicationContext("classpath:spring/quartz.xml");
23. logger.debug("Run QuartzApp");
24. }
25. }

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的配置了,我们逐条来看:
Xml代码

1. <!-- Service配置 -->
2. <bean id="quartzService"
3. class="org.ourpioneer.service.QuartzService"></bean>

<!-- Service配置 -->
<bean id="quartzService"
class="org.ourpioneer.service.QuartzService"></bean>


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

1. <!-- 定义调度对象和调用的方法 -->
2. <bean id="quartzJob"
3. class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
4. <property name="targetObject">
5. <bean class="org.ourpioneer.quartz.job.QuartzJob">
6. <property name="quartzService" ref="quartzService" />
7. </bean>
8. </property>
9. <property name="targetMethod">
10. <value>execute</value>
11. </property>
12. </bean>

<!-- 定义调度对象和调用的方法 -->
<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,这里一样。所以这就体现了配置的灵活性。
调度程序有了,那么要定时执行,怎么来告诉控制程序来执行呢?监听时间,没错,这里使用的就是这种机制,不过不是监听器,监听器是监听事件的发生,而不能监听时间的到达,这里就是触发器,但和数据库的触发器不同,数据库的触发器还是监听了数据操作的事件,而不是时间。定点触发调度程序,要配置触发器:
Xml代码

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

<!-- 配置触发器 -->
<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的关系图,更直观一点:

这里就看出了它们之间的依赖关系,下面我们来测试,启动主函数运行:

本文系作者的实践探索,希望对使用者有用,欢迎交流。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值