Spring集成Quartz配置动态任务

作者: tcxurun 分类: Java 发布时间: 2013-09-01 21:15 ė 6 没有评论

在开发的项目中有一个需求,需要灵活配置调度任务时间,并能自由启动或停止调度。 马上想到了在另外一个项目中用到的Quartz这个开源调度组件它提供了强大的任务调度机制,允许开发人员灵活的定义触发器的调度时间,并可对触发器和任务进行关联映射。此外,Quartz提供了调度运行环境的持久化机制,可以保存并恢复调度现场,即使系统因故障关闭,任务调度现场数据并不会丢失。

Quartz对任务调度的领域问题进行了高度抽象,提出了调度器、任务和触发器这三个核心概念。

1 Job:这是quartz的任务接口。Job来决定了任务是干什么的。Job暴露了一个接口execute,这里是我们写我们的任务逻辑的地方。Job运行时的信息保存在JobDataMap实例中。

2 JobDetail:这也是quartz的一个接口,它其中存放了Job.class和Job的一些描述性信息,例如Job的名字、组名等。
2 Trigger:这是quartz的触发器。它决定了绑定的JobDetail什么时候执行,就是决定任务的执行的时间规则。

3 Calender是quartz的日历接口。它决定绑定的任务(JobDetails)什么时候不执行。Trigger是决定什么时候执行。二者可以配合使用。例如每月一号执行,但是1月1号不执行。

4 Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler。Scheduler可以将Trigger绑定到某一个JobDetail中,这样当Trigger被触发时,对应的Job就被执行。一个Scheduler可以拥有多个Trigger和多个JobDatail,一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。

5 ThreadPool:这是quartz暴露的一个线程池接口。线程池是任务执行的基础。在并发任务下,每个任务启用一个线程,如果线程池中的线程已经用完,再来任务时需要等待,直到有线程可用。如果等待时间过长,超过了org.quartz.jobStore.misfireThreshold设置的时间,任务不再执行。

Job有一个StatefulJob子接口,代表有状态的任务,该接口是一个没有方法的标签接口,其目的是让Quartz知道任务的类型,以便采取不同的执行方案。无状态任务在执行时拥有自己的JobDataMap复制,对JobDataMap的更改不会影响下次的执行,而又状态的任务共享同一个JobDataMap实例,每次任务执行对JobDataMap所做的更改会保存下来,后面的执行可以看到这个更改,即每次执行任务后对后面的执行发生影响。

因此,无状态的Job可以并发执行,而有状态的StatefulJob不能并发执行,也就是如果前次的StatefulJob还没有执行完毕,下一次的任务将阻塞等待,直到前次任务执行完毕。有状态任务比无状态任务需要考虑更多的因素,程序往往更复杂,因此除非必要,应尽量避免使用有状态的Job。

如果Quartz使用了数据库持久化任务调度信息,无状态的JobDataMap仅会在Scheduler注册任务时保存一次,而有状态任务对应的JobDataMap在每次执行任务后都会进行保存。

Spring为创建Quartz的Scheduler、Trigger和JobDetail提供了便利的FactoryBean类,以便在Spring容器中享受到注入的好处。所以Spring结合Quartz静态配置调度任务时间,非常easy。

通常情况下,任务都定义在一个业务类方法中。但是按照Quartz Job接口的定义,需要定义一个引用业务类方法的实现类。为了避免创建这个只包含一行调用代码的Job实现类,Spring提供了MethodInvokingJobDetailFactoryBean,借由该FactoryBean,可以将一个Bean的某个方法封装成满足Quartz要求的Job,示例代码使用的就是这种方式。

具体的任务如下:
一、编写业务类
二、配置spring的applicationContext.xml文件
1 配置任务JobDetailBean
2 配置触发器CrontriggerBean
3配置调度器 SchedulerFactoryBean
三、把quartz.properties放到类路径下

<!--  quartz定时器配置 -->
<bean id="emailTask"
	class="com.quartzdemo.service.impl.CheckSendEmail" />

<bean id="jobDetailBean"
	class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	<property name="targetObject" ref="emailTask"></property>

	<property name="targetMethod" value="execute"></property>
</bean>

<!-- 触发器 -->
<bean id="cronTrigger"
	class="org.springframework.scheduling.quartz.CronTriggerBean">
	<!-- 指向我们的任务 -->
	<property name="jobDetail" ref="jobDetailBean" />
	<!-- 执行时间  每天上午11点运行-->
	<property name="cronExpression" value="0 0 11 * * ?" />
</bean>
<!-- 调度器 -->
<bean id="schdulerFactory" lazy-init="false"
	class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<property name="triggers">
		<list>
			<!-- 触发器列表 -->
			<ref bean="cronTrigger" />
		</list>
	</property>
	<property name="configLocation"
		value="classpath:quartz.properties">
	</property>
</bean>

jobDetailBean将emailTask#execute方法封装成一个任务,此处没有设置任务的类型,默认情况下封装成武状态的任务。execute方法可以是static,也可以是非static的,但不能拥有方法入参。通过MethodInvokingJobDetailFactoryBean产生的JobDetail不能被序列化,所以不能被持久化到数据库中,如果希望使用持久化任务,用户只能创建正规的Quartz的Job实现类了。

cronExpression表达式就不说了,可以在网上查到相关资料。

使用的jar包主要是spring和quartz,也可以在网上找到。

quartz.properties文件的内容(默认放在类路径下)

# Configure Main Scheduler Properties  
#============================================================================
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false

#============================================================================
# Configure ThreadPool  
#============================================================================
#org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

#============================================================================
# Configure JobStore  
#============================================================================
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.misfireThreshold = 60000
#org.quartz.jobStore.useProperties = false
#org.quartz.jobStore.tablePrefix = QRTZ_
#org.quartz.jobStore.dataSource = myDS

#org.quartz.jobStore.isClustered = true
#org.quartz.jobStore.clusterCheckinInterval = 15000

#============================================================================
# Configure DataSource
#============================================================================
org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost/test
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password = root
org.quartz.dataSource.myDS.maxConnections = 10

本文出自天一直很蓝,转载时请注明出处及相应链接。

本文永久链接: http://www.tcxurun.cn/archives/73

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Ɣ回顶部