1、 Spring 的org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean类,使用此方法使开发人员对Quartz完全透明,需要实现定时任务的方法只是一个普通方法。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- 方法一: Spring 的org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean类, 使用此方法使开发人员对Quartz完全透明,需要实现定时任务的方法只是一个普通方法。 --> <!--1、 配置文件中添加业务类,该类为调用的工作类 --> <bean id="businessWork" class="com.morningstar.quartz.BusinessWork" /> <!-- 2、定义任务,在spring文件中配置代理类 ,定义调用对象和调用对象的方法--> <bean id="businessTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <!-- 调用的类 --> <property name="targetObject" ref="businessWork"/> <!-- 调用类中的方法 --> <property name="targetMethod" value="generateReport"/> <!-- false,证明不执行并发任务 --> <property name="concurrent" value="false"/> </bean> <!-- 3、配置触发器,定义触发时间,可以根据不同的时间对同一个任务定义多个触发器,下面是每隔5秒调用一个方法配置--> <!-- cron表达式 --> <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="businessTask"/> <property name="cronExpression" value="10,15,20,25,30,35,40,45,50,55 * * * * ?"/> </bean> <!-- 4、配置调度器 ,容器启动就会执行调度程序 --> <!-- 总管理类,如果lazy-init=‘false‘,则容器启动时就会执行调度程序--> <!-- 如果lazy-init=‘true‘,则需要实例化该bean才能执行调度程序 --> <bean id="schdulerFactory" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger"/> </list> </property> </bean> </beans>
2、借助于Spring的org.springframework.scheduling.quartz.JobDetailBean的类功能, 继承 Spring封装Quartz的org.springframework.scheduling.quartz.QuartzJobBean类,实现 executeInternal方法,executeInternal方法中调用业务类。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- 方法二: 借助于Spring的org.springframework.scheduling.quartz.JobDetailBean的类功能, 继承 Spring封装Quartz的org.springframework.scheduling.quartz.QuartzJobBean类,实现 executeInternal方法, executeInternal方法中调用业务类 --> <!-- 1、定义任务,在spring文件中配置代理类 ,定义调用对象和调用对象的方法--> <bean id="businessTask" class="org.springframework.scheduling.quartz.JobDetailBean"> <!-- 调用的类 --> <property name="jobClass" value="com.morningstar.quartz.BusinessWork"/> <!-- 主要是为了在定时任务需要使用到Bean,通过Spring给注入进来,如果不写明,就会报java.lang.NullPointerException错误 --> <!-- <property name="jobDataAsMap"> <map> <entry key="someService"> <ref bean="someService" /> </entry> </map> </property> --> </bean> <!-- 2、配置触发器,定义触发时间,可以根据不同的时间对同一个任务定义多个触发器--> <!-- cron表达式 --> <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="businessTask"/> <property name="cronExpression" value="10,15,20,25,30,35,40,45,50,55 * * * * ?"/> </bean> <!-- 3、配置调度器 ,容器启动就会执行调度程序 --> <!-- 总管理类,如果lazy-init=‘false‘,则容器启动时就会执行调度程序--> <!-- 如果lazy-init=‘true‘,则需要实例化该bean才能执行调度程序 --> <bean id="schdulerFactory" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger"/> </list> </property> </bean> </beans>
Quartz 是优秀的开源的任务调度框架,它提供了强大任务调度机制。Quartz允许开发人员定义触发器的调度时间表,并提供了触发器和任务之间的关联映射。此外,Quartz提供了调度运行环境的持久化机制,可以保存并恢复调度现场,即使系统因故障关闭,任务调度现场数据并不会丢失。此外,Quartz还提供了组件式的侦听器、各种插件、线程池等功能。
Spring为创建Quartz的Scheduler、Trigger和JobDetail提供了便利的FactoryBean类,以便能够在Spring 容器中享受注入的好处,主要有以下两个方面:
1)为Quartz的重要组件类提供更具Bean风格的扩展类;
2)提供创建Scheduler的BeanFactory类,方便在Spring环境下创建对应的组件对象,并结合Spring容器生命周期进行启动和停止的动作。
1)为Quartz的重要组件类提供更具Bean风格的扩展类;
2)提供创建Scheduler的BeanFactory类,方便在Spring环境下创建对应的组件对象,并结合Spring容器生命周期进行启动和停止的动作。
JobDetailBean
关于JobDetail, Spring通过扩展JobDetail提供了一个JobDetailBean(org.springframework.scheduling.quartz包里)。JobDetailBean可以配置以下属性,其任务类如果实现了org.quartz.Job,则jobDataAsMap的值的修改无法保留到下一次执行,如果实现了org.quartz.StatefulJob:
关于JobDetail, Spring通过扩展JobDetail提供了一个JobDetailBean(org.springframework.scheduling.quartz包里)。JobDetailBean可以配置以下属性,其任务类如果实现了org.quartz.Job,则jobDataAsMap的值的修改无法保留到下一次执行,如果实现了org.quartz.StatefulJob:
●
jobClass:类型为Class,实现Job/StatefulJob接口的任务类;
● beanName:默认为Bean的id名,通过该属性显式指定Bean名称,它对应任务的名称;
● jobDataAsMap:类型为Map,为任务所对应的JobDataMap提供值。Spring通过jobDataAsMap设置JobDataMap的值;
● applicationContextJobDataKey:你可以将Spring ApplicationContext的引用保存到JobDataMap中,以便在Job的代码中访 问ApplicationContext。为了达到这个目的,你需要指定一个键,用以在jobDataAsMap中保存ApplicationContext,如果不设置此键,JobDetailBean就不将ApplicationContext放入到JobDataMap中。
● jobListenerNames:类型为String[],指定注册在Scheduler中的JobListeners名称,以便让这些监听器对本任务的事件进行监听。
● beanName:默认为Bean的id名,通过该属性显式指定Bean名称,它对应任务的名称;
● jobDataAsMap:类型为Map,为任务所对应的JobDataMap提供值。Spring通过jobDataAsMap设置JobDataMap的值;
● applicationContextJobDataKey:你可以将Spring ApplicationContext的引用保存到JobDataMap中,以便在Job的代码中访 问ApplicationContext。为了达到这个目的,你需要指定一个键,用以在jobDataAsMap中保存ApplicationContext,如果不设置此键,JobDetailBean就不将ApplicationContext放入到JobDataMap中。
● jobListenerNames:类型为String[],指定注册在Scheduler中的JobListeners名称,以便让这些监听器对本任务的事件进行监听。
***此外,Spring提供了一个MethodInvokingJobDetailFactoryBean,通过这个FactoryBean可以将Spring容器中Bean的方法包装成Quartz任务,这样开发者就不必为Job创建对应的类。否则该类只是简单包含调用Bean的方法,并无实际使用价值。这个FactoryBean的配置实例如下(假设封装businessBean的schedulerMethod方法,以有状态Job调度,即其中的JobDataMap将得到维持,concurrent默认为true,即无状态Job调度):
<bean id="methodJobSmp"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property
name="targetObject" ref="businessBean" />
<property
name="targetMethod" value="schedulerMethod" />
<property
name="concurrent" value="false" />
</bean>
注意:其中的schedulerMethod方法即可以是static,也可以是非static的,但不能拥有方法入参。通过MethodInvokingJobDetailFactoryBean产生的JobDetail不能被序列化,所以不能被持久化到数据库中的,如果希望使用持久化任务,则你只能创建正规的Quartz的Job实现类了。
有了JobDetail作为具体任务,我们还需要Spring帮我们调度到调度器里去生效。Spring可以配置三种调度,其中简单调度SimpleTriggerBean,定时调度CronTriggerBean是为Quartz扩展(org.springframework.scheduling.quartz包里),还自己提供了计时调度ScheduledTimerTask(org.springframework.scheduling.timer里)。
SimpleTriggerBean配置实例如下(任务为jobDetailBeanName,是一个JobDetailBean的id,可是是具体实现类,也可以是MethodInvokingJobDetailFactoryBean配置的代理类;延迟10秒后启动,时间间隔为20秒,重复执行100次,配置任务变量count值为10):
<bean id="simpleTrigger1"
class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail"
ref="jobDetailBeanName" />
<property name="startDelay"
value="1000" />
<property name="repeatInterval"
value="2000" />
<property name="repeatCount"
value="100" />
<property
name="jobDataAsMap">
<map>
<entry key="count" value="10"
/>
</map>
</property>
</bean>
CronTriggerBean配置实例如下(任务为jobDetailBeanName,调度时间表是每天每隔三小时运行(0点,3点,6点,…)
<bean id="cronTriggerSmp"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property
name="jobDetail" ref="jobDetailBeanName"/>
<property
name="cronExpression" value="0 0 */3 * * ? *"/>
</bean>
cronExpression的表示式规范:
域名
|
强制?
|
允许值范围
|
支持的特殊字符
|
秒
|
是
|
0-59
|
- * /
|
分
|
是
|
0-59
|
- * /
|
时
|
是
|
0-23
|
- * /
|
日
|
是
|
1-31
|
- * / ? L W C
|
月
|
是
|
1-12
|
- * /
|
星期
|
是
|
1-7(SUN-SAT)
|
- * / ? L C #
|
年
|
非空
|
1970-2099
|
- * /
|
计时调度ScheduledTimerTask配置实例如下(任务为jobDetailBeanName,执行间歇间隔为60秒,执行间隔为3600000毫秒)
<bean id="timerTaskExample"
class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property
name="delay" value="60"/>
<property
name="period" value="3600000"/>
<property
name="timerTask" ref="jobDetailBeanName"/>
</bean>
有了调度项,我们可以把他们简单添加到调度器里去即可。Spring为计时调度ScheduledTimerTask提供了调度器工厂BEAN--TimerFactoryBean(org.springframework.scheduling.timer包里),该调度器配置实例如下:
<bean id="timeSample"
class="org.springframework.scheduling.timer.TimerFactoryBean">
<property
name="scheduledTimerTasks">
<list>
<ref
bean=" timerTaskExample "/><!—可以很多 -->
</list>
</property>
</bean>
Sprint还为扩展Quartz的调度CronTriggerBean、SimpleTriggerBean也扩展了调度器工厂BEAN—SchedulerFactoryBean(org.springframework.scheduling.quartz包里),其配置实例如下:
<bean id="scheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property
name="autoStartup"><!-初始化后是否马上启动Scheduler,默认是true. -->
<value>true</value>
</property>
<property
name="startupDelay"><!-初始化后是否延时多少秒启动Scheduler,默认是0马上启动,通过startupDelay属性让Scheduler延迟一小段时间后启动,以便让Spring能够更快初始化容器中剩余的Bean.
-->
<value>0</value>
</property>
<property
name="triggers">
<list>
<ref
local="simpleTrigger1"/>
<ref
local="cronTriggerSmp
"/>
<ref
local="quartzTrigger1"/>
</list>
</property>
<property
name="schedulerContextAsMap"> <!—context setting -->
<map>
<entry
key="keya" value="valuea"/>
</map>
</property>
<property name="configLocation"
value="classpath:com/coma/projb/quartz/quartz.properties" />
</bean>
还有calendars属性(类型为Map,通过该属性向Scheduler注册Calendar),jobDetails属性(类型为JobDetail[],通过该属性向Scheduler注册JobDetail)用得不多。
SchedulerFactoryBean还可以通过以下属性代替框架的自身配置文件:
● dataSource:当需要使用数据库来持久化任务调度数据时,你可以在Quartz中配置数据源,也可以直接在Spring中通过dataSource指定一个Spring管理的数据源。如果指定了该属性,即使quartz.properties中已经定义了数据源,也会被此dataSource覆盖;
● transactionManager:可以通过该属性设置一个Spring事务管理器。在设置dataSource时,Spring强烈推荐你使用一个事务管理器,否则数据表锁定可能不能正常工作;
● nonTransactionalDataSource:在全局事务的情况下,如果你不希望Scheduler执行化数据操作参与到全局事务中,则可以通过该属性指定数据源。在Spring本地事务的情况下,使用dataSource属性就足够了;
● quartzProperties:类型为Properties,允许你在Spring中定义Quartz的属性。其值将覆盖quartz.properties配置文件中的设置,这些属性必须是Quartz能够识别的合法属性,配置quartzProperties属性实例如下:
● dataSource:当需要使用数据库来持久化任务调度数据时,你可以在Quartz中配置数据源,也可以直接在Spring中通过dataSource指定一个Spring管理的数据源。如果指定了该属性,即使quartz.properties中已经定义了数据源,也会被此dataSource覆盖;
● transactionManager:可以通过该属性设置一个Spring事务管理器。在设置dataSource时,Spring强烈推荐你使用一个事务管理器,否则数据表锁定可能不能正常工作;
● nonTransactionalDataSource:在全局事务的情况下,如果你不希望Scheduler执行化数据操作参与到全局事务中,则可以通过该属性指定数据源。在Spring本地事务的情况下,使用dataSource属性就足够了;
● quartzProperties:类型为Properties,允许你在Spring中定义Quartz的属性。其值将覆盖quartz.properties配置文件中的设置,这些属性必须是Quartz能够识别的合法属性,配置quartzProperties属性实例如下:
bean id="scheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property
name="quartzProperties">
<props>
<prop
key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
<prop
key="org.quartz.threadPool.threadCount">10</prop>
</props>
</property>
</bean>