使用方法
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又是單繼承……