使用方法
quartz是一個強大的任務調度框架,利用spring將其整合,添加較少的配置即可快速使用,主要步驟如下:
0. 導入需要的jar包或添加依賴,主要有spring-context-support、spring-tx、quartz;
1. 編寫被調度類和被調度方法,即需要定時執行的類和方法;
2. 在spring容器中注冊被調度類,單個注冊或包掃描均可;
3. 在spring容器中注冊作業類(MethodInvokingjOBdetailFactoryBean),並注入被調度類和被調度方法,一般每個被調度方法需要注冊一個作業類;
4. 在spring容器中注冊觸發器,並注入對應的作業類和觸發條件,一般每個作業類需要注冊一個觸發器;
觸發器是用來指定被調度方法的執行時間的,根據觸發條件的不同,有兩個類可以選擇:
(1) SimpleTriggerFactoryBean,只能指定間隔固定時長執行,例如每隔5秒鍾執行一次;
(2) CronTriggerFactoryBean,既可以指定間隔固定時長執行,也可以指定某個或某幾個時刻執行,例如每周三下午16點;
5. 在spring容器中注冊調度工廠(ScheduerFactoryBean),並注入需要的觸發器,可以注入一個或多個觸發器。
示例Demo
被調度類和被調度方法
/** * 使用quartz框架實現定時任務 * 被調度類 * created on 2019-04-20 */ public class QuartzJob { /** * 定時方法,使用固定時長指定執行時間 */ public void doSimpleBusiness() { //業務邏輯省略,僅測試能執行方法 System.out.println("----------quartz + 固定時長----------"); } /** * 定時方法,使用cron表達式指定執行時間 */ public void doCronBusiness() { //業務邏輯省略,僅測試能執行方法 System.out.println("----------quartz + cron表達式----------"); } }
spring配置文件
<?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.xsd"> <!--注冊被調度類--> <bean id="quartzJob" class="cn.monolog.diana.quartz.QuartzJob" /> <!--注冊固定時長的作業類,並注入被調度類和被調度方法--> <bean id="jobDetail1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="quartzJob" /> <property name="targetMethod" value="doSimpleBusiness" /> </bean> <!--注冊固定時長的觸發器,並注入相應的作業類和間隔時間(單位為毫秒)--> <bean id="trigger1" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> <property name="jobDetail" ref="jobDetail1" /> <property name="repeatInterval" value="3000" /> </bean> <!--注冊cron表達式的作業類,並注入被調度類和被調度方法--> <bean id="jobDetail2" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="quartzJob" /> <property name="targetMethod" value="doCronBusiness" /> </bean> <!--注冊cron表達式的觸發器,並注入相應的作業類和cron表達式--> <bean id="trigger2" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="jobDetail2" /> <property name="cronExpression" value="0/4 * * * * ?" /> </bean> <!--注冊調度工廠,並注入需要生效的觸發器,注意最后autowire的配置--> <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" autowire="no"> <property name="triggers"> <list> <ref bean="trigger1" /> <ref bean="trigger2" /> </list> </property> </bean> </beans>
踩過的坑
1. 一開始只是添加了spring-context-support和quartz依賴,結果服務啟動失敗,異常日志如下:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'schedulerFactory' defined in class path resource [applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.scheduling.quartz.SchedulerFactoryBean]: No default constructor found; nested exception is java.lang.NoClassDefFoundError: org/springframework/transaction/TransactionException
乍一看是因為初始化ScheduerFactoryBean失敗,因為沒有默認的構造器,后面又說是沒有關於TransactionException的定義。但是我這個demo並沒有用到事務,跟TransactionException有啥關系?暫時找不到內在聯系,但是既然提示了,就加關於事務的依賴試一下。果然,添加了spring-tx的依賴之后,服務啟動成功。至於為什么初始化ScheduerFactoryBean需要用到事務,待日后找到答案再來更新。
2. 一開始在配置文件中注冊調度工廠並沒有加autowire屬性,啟動服務時報錯,無法啟動quartz觸發器,因為表不存在,異常日志如下:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'sm4_console.QRTZ_TRIGGERS' doesn't exist
參考了這位大神的博文https://www.cnblogs.com/gmq-sh/p/4328317.html,大概意思是quartz會使用數據庫記錄被調度類的狀態,而數據庫中並不存在這些日志表。解決方法就是在配置文件注冊調度工廠時加autowire屬性配置。
其他整合方案
除了上述,spring還提供了另外一種整合quartz的方案,即被調度類需要繼承QuartzJobBean類,其他配置方式類似。
但是這種方案顯然不如第一種靈活,因為被調度類需要繼承固定的類,而Java又是單繼承……