`
sarin
  • 浏览: 1748031 次
  • 性别: Icon_minigender_1
  • 来自: 大连
博客专栏
E3b14d1f-4cc5-37dd-b820-b6af951740bc
Spring数据库访问系列...
浏览量:172820
C2083dc5-6474-39e2-993e-263652d27795
Android学习笔记
浏览量:366550
5f40a095-b33c-3e8e-8891-606fcf3b8d27
iBatis开发详解
浏览量:188306
B272a31d-e7bd-3eff-8cc4-c0624ee75fee
Objective-C学习...
浏览量:98742
社区版块
存档分类
最新评论

Spring支持的Quartz程序调度

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

    我们在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的关系图,更直观一点:

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

    本文系作者的实践探索,希望对使用者有用,欢迎交流。
  • 大小: 48.5 KB
  • 大小: 28.7 KB
  • 大小: 143.5 KB
21
2
分享到:
评论
10 楼 sarin 2012-08-22  
2110901055 写道
sarin 写道
2110901055 写道
您好,假如是现在要知道任务的真正执行次数怎么办?而不是数据库中有一个字段表示的任务触发的次数,谢谢。

每次执行后调用JDBC更新数据库

您好,我的思路也是这样,但不知道quartz本身调用数据库存储它本身的数据是在什么时候?在哪儿?我假如另外在再建一个字段在JOB本身的exceute方法中去更新与调用的话感觉太麻烦,利用它本身的操作我去增加点逻辑处理这样行么,怎么做?谢谢。

Quartz没有这个功能,请在Service类中注入JDBC访问的接口即可调用JDBC更新数据库
9 楼 2110901055 2012-08-22  
sarin 写道
2110901055 写道
您好,假如是现在要知道任务的真正执行次数怎么办?而不是数据库中有一个字段表示的任务触发的次数,谢谢。

每次执行后调用JDBC更新数据库

您好,我的思路也是这样,但不知道quartz本身调用数据库存储它本身的数据是在什么时候?在哪儿?我假如另外在再建一个字段在JOB本身的exceute方法中去更新与调用的话感觉太麻烦,利用它本身的操作我去增加点逻辑处理这样行么,怎么做?谢谢。
8 楼 sarin 2012-08-21  
2110901055 写道
您好,假如是现在要知道任务的真正执行次数怎么办?而不是数据库中有一个字段表示的任务触发的次数,谢谢。

每次执行后调用JDBC更新数据库
7 楼 2110901055 2012-08-21  
您好,假如是现在要知道任务的真正执行次数怎么办?而不是数据库中有一个字段表示的任务触发的次数,谢谢。
6 楼 sarin 2010-09-15  
yuantong 写道
2010-09-15 16:11:42,671 DEBUG [QuartzService.java:17] - Construct QuartzService
2010-09-15 16:11:42,718 DEBUG [QuartzJob.java:25] - Construct QuartzJob
2010-09-15 16:11:42,718 DEBUG [QuartzJob.java:21] - QuartzService Injection
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'startQuartz' defined in class path resource [spring/quartz.xml]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: javax/transaction/UserTransaction
Caused by: java.lang.NoClassDefFoundError: javax/transaction/UserTransaction

java.lang.NoClassDefFoundError,没有参照的类,这个类是javax/transaction/UserTransaction,也就是虚拟机运行时没有找到它,看看是什么原因吧。
5 楼 yuantong 2010-09-15  
2010-09-15 16:11:42,671 DEBUG [QuartzService.java:17] - Construct QuartzService
2010-09-15 16:11:42,718 DEBUG [QuartzJob.java:25] - Construct QuartzJob
2010-09-15 16:11:42,718 DEBUG [QuartzJob.java:21] - QuartzService Injection
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'startQuartz' defined in class path resource [spring/quartz.xml]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: javax/transaction/UserTransaction
Caused by: java.lang.NoClassDefFoundError: javax/transaction/UserTransaction
at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1104)
at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1355)
at org.springframework.scheduling.quartz.SchedulerFactoryBean.createScheduler(SchedulerFactoryBean.java:668)
at org.springframework.scheduling.quartz.SchedulerFactoryBean.afterPropertiesSet(SchedulerFactoryBean.java:568)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1062)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1029)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:420)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:247)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:178)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:244)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:158)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:287)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:348)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:92)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:77)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:68)
at org.ourpioneer.quartz.app.QuartzApp.main(QuartzApp.java:22)
4 楼 sjbwylbs 2010-09-09  
简单的Quartz例程..不用JobDetail的MethodInvokingJobDetailFactoryBean的使用
3 楼 sarin 2010-09-06  
liliugen 写道
放个demo上来更直观,

好的,今晚上传DEMO,不含类库
2 楼 liliugen 2010-09-06  
放个demo上来更直观,
1 楼 zerxd 2010-09-05  
aaaaaaa

相关推荐

Global site tag (gtag.js) - Google Analytics