在前面的文章中,我們已實現了在 SpringBoot 項目中執行定時任務
但是,自帶的定時任務有其侷限性,比如在分佈式環境中無法協調多節點,就會導致一個任務會在多個節點同時執行。
接下來,我們將實現對開源作業調度框架 Quartz 的整合。
相關知識
什麼是 Quartz
Quartz 是一個完全由 Java 編寫的開源作業調度框架,爲在 Java 應用程序中進行作業調度提供了簡單卻強大的機制。
Quartz 的特點
作爲一個優秀的開源調度框架,Quartz 具有以下特點:
- 強大的調度功能,例如支持豐富多樣的調度方法,可以滿足各種常規及特殊需求
- 靈活的應用方式,例如支持任務和調度的多種組合方式,支持調度數據的多種存儲方式
- 分佈式和集羣能力,Terracotta 收購後在原來功能基礎上作了進一步提升
- Quartz 很容易與 Spring 集成實現靈活可配置的調度功能
Quartz 相關概念
- scheduler:任務調度器
Quartz 提供了 DirectSchedulerFactory 及 StdSchedulerFactory 工廠類用於創建。通常使用 StdSchedulerFactory 進行創建。
- trigger:觸發器,用於定義任務調度時間規則。
Quartz 中主要提供了四種類型的 trigger:SimpleTrigger,CronTirgger,DateIntervalTrigger,和 NthIncludedDayTrigger。這四種 trigger 可以滿足企業應用中的絕大部分需求。
- job:被調度的任務,一個 job 可以被多個 trigger 關聯,但是一個 trigger 只能關聯一個 job
job 有兩種類型:無狀態的(stateless)和有狀態的(stateful)。
對於同一個 trigger 來說,有狀態的 job 不能被並行執行,只有上一次觸發的任務被執行完之後,才能觸發下一次執行。
Job 主要有兩種屬性:volatility 和 durability,
其中 volatility 表示任務是否被持久化到數據庫存儲,
而 durability 表示在沒有 trigger 關聯的時候任務是否被保留。
兩者都是在值爲 true 的時候任務被持久化或保留。
目標
簡單整合 Quartz,實現使用 Quartz 執行定時任務
操作步驟
添加依賴
引入 Spring Boot Starter 父工程
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
添加 spring-boot-starter-quartz
的依賴,添加後的整體依賴如下
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
</dependencies>
編碼
編寫定時任務執行類
- @DisallowConcurrentExecution 用於處理任務併發執行的問題。
- @PersistJobDataAfterExecution 成功執行了job類的execute方法後(沒有發生任何異常),更新JobDetail中JobDataMap的數據,
使得該job(即JobDetail)在下一次執行的時候,JobDataMap中是更新後的數據,而不是更新前的舊數據。
最好與 @DisallowConcurrentExecution 註解同時使用,以防止併發造成 JobDataMap 中存儲的數據不確定。
@Data
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class TimeJob extends QuartzJobBean {
private String name;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
System.out.println("execute timeJob at " +
LocalDateTime.now().format(DateTimeFormatter.ofPattern("hh:mm:ss")) +
": hello " + this.name);
}
}
註冊定時任務
- 註冊
JobDetail
,內部維護了一個 JobDataMap 數據容器與外界進行交互,可以通過usingJobData
方法,爲定時任務傳遞數據 - 註冊
Trigger
,關聯JobDetail
,並設置定時任務執行策略
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public JobDetail sampleJobDetail() {
return JobBuilder.newJob(TimeJob.class).withIdentity("timeJob")
.usingJobData("name", "Quartz").storeDurably().build();
}
@Bean
public Trigger sampleJobTrigger() {
// 如果需要使用 cronExpression 表達式,則使用 CronScheduleBuilder 進行創建
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2).repeatForever();
return TriggerBuilder.newTrigger().forJob(sampleJobDetail())
.withIdentity("timeTrigger").withSchedule(scheduleBuilder).build();
}
}
驗證
啓動項目,查看日誌
execute timeJob at 08:24:06: hello Quartz
execute timeJob at 08:24:08: hello Quartz
execute timeJob at 08:24:10: hello Quartz
源碼地址
本章源碼 : https://gitee.com/gongm_24/spring-boot-tutorial.git
結束語
本文實現了對 Quartz 框架的基本整合,通過硬編碼實現任務及執行策略的註冊。
接下來我們將實現動態管理任務及執行策略,包括增刪查改、暫停及重啓任務,敬請期待。