【Quartz】Integration with Spring


Spring目前支持两种定时任务集成,Timer(since JDK1.3)和Quartz,这篇主要说说Quartz。

将Quartz集成到Spring主要是通过创建FactoryBean并为其添加一些引用。

而且我们可以通过MethodInvokingFactoryBeans非常方便的引用任何一个对象的方法。


首先需要理清Quartz本身的一些概念,Trigger、Job、JobDetail等等。

(请参考http://quartz-scheduler.org/documentation/quartz-2.2.x/tutorials)

为了简化其在Spring应用中的使用,Spring为用户提供了一些相关的class。



1.org.springframework.scheduling.quartz.JobDetailBean

JobDetail对象拥有某个任务的所有信息。

相应地,Spring提供了JobDetailBean。

需要注意的是,JobDetailBean不适用于Quartz2.0以上的版本。

如果需要考虑兼容性,我们可以用JobDetailFactoryBean来代替。


顺便一提,我加的dependency是2.2.1的,我只能用JobDetailFactoryBean

		<!-- quartz scheduler -->
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>2.2.1</version>
		</dependency>
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz-jobs</artifactId>
			<version>2.2.1</version>
		</dependency>


下面是一个例子,定义一个job:

public class MinutePrintJob extends QuartzJobBean {

	@Override
	protected void executeInternal(JobExecutionContext context)
			throws JobExecutionException {
		logger.info("Current Time:::"+new Date());
	}

	static final Logger logger = LoggerFactory.getLogger(MinutePrintJob.class);
}


定义一个job bean:

	<bean id="printJob"
		class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
		<property name="jobClass" value="pac.king.schedule.MinutePrintJob" />
		<property name="durability" value="true" />
		<property name="jobDataAsMap">
			<map>
				<entry key="timeout" value="5" />
			</map>
		</property>
	</bean>


上面的例子中我们将timeout属性放到了jobDataAsMap中。(PS:JobDataMap对象可以在JobExecutionContext中获取)

另外JobDetailBean也可以将JobDataMap中的属性映射到某个Job对象的field中,即我们也可以在Job中得到这些属性。

(还是PS:别忘了setter)


比如以下代码,timeout输出5:

public class MinutePrintJob extends QuartzJobBean {
	
	private int timeout;
	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	@Override
	protected void executeInternal(JobExecutionContext context)
			throws JobExecutionException {
		logger.info("Current Time:::"+new Date()+"\t timeout::"+timeout);
	}
	
	static final Logger logger = LoggerFactory.getLogger(MinutePrintJob.class);
}



2.org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean

如果我想调用某个已定义的方法,但我又觉得再新建一个class写一行代码去调用这个方法很蠢。

此时我们可以用MethodInvokingJobDetailFactoryBean,仅仅改变一下配置就让它生效。

比如,我在MinutePrintJob中加了个...(当然他不是复写QuartzJobBean的方法..你可以把他定义在任何地方)

	public void justDoIt(){
		logger.info("Kim say:just do it!!");
	}


定义一个methodInvokingJobDetailFactoryBean....并根据需要让特定的trigger负责该job:

	<bean id="minPrintJob" class="pac.king.schedule.MinutePrintJob"></bean>
	<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject" ref="minPrintJob" />
		<property name="targetMethod" value="justDoIt" />
	</bean>


需要注意的是,默认时job都是无状态的,多个job可以影响彼此。

比如两个trigger引用了相同的JobDetail,并且在第一个job没有结束执行,第二个job就开始执行。

我们可以为JobDetail加个状态以让job不要并发执行。

MethodInvokingJobDetailFactoryBean的concurrent属性恰恰是解决这一问题的:

	<bean id="minPrintJob" class="pac.king.schedule.MinutePrintJob"></bean>
	<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject" ref="minPrintJob" />
		<property name="targetMethod" value="justDoIt" />
		<property name="concurrent" value="false" />
	</bean>

(PS:concurrent默认为true!)



3.CronTriggerBean and SimpleTriggerBean

声明好job和jobDetail后,我们需要为他们安排时间执行。

虽然Quartz提供了一些trigger,Spring还额外提供了两个子类。


这两个类没有太多说明(两者javadoc的内容几乎相同),仅用于简化配置,使用方法如下:

<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
  <property name="jobDetail" ref="jobDetail"/>
  <property name="startDelay" value="5000"/>
  <property name="repeatInterval" value="15000"/>
</bean>
 
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
  <property name="jobDetail" ref="exampleJob"/>
  <property name="cronExpression" value="0 0 6 * * ?"/>
</bean>

(cronExpression格式请参考http://quartz-scheduler.org/api/2.1.0/org/quartz/CronExpression.html)



剩下的工作就是将这些trigger配置到SchedulerFactoryBean:

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  <property name="triggers">
    <list>
      <ref bean="cronTrigger"/>
      <ref bean="simpleTrigger"/>
    </list>
  </property>
</bean>


更多属性根据具体需求进行设置 i_f29.gif

另外,我用的是MySQL。

虽然可以在schedulerFactoryBean中配置dataSource,但我还是在quartz.properties中配置了数据源。

但这样就不能指定自己喜欢的Database Connection Pools实现,quartz默认用c3p0作为实现。

仅供参考:

#============================================================================ 
# Configure Datasources 
#============================================================================ 
org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 
org.quartz.dataSource.myDS.user = root 
org.quartz.dataSource.myDS.password = 
org.quartz.dataSource.myDS.maxConnections = 5


你可能感兴趣的:(spring,quartz,scheduler)