天天看點

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

作者:程式設計俠Java

在項目開發過程中,有時候需要利用定時任務技術來完成某些周期性的任務,比如,定時下載下傳對賬單、定時進行資料對比、轉換,資料定時入庫等等。在最開始的時候部分開發人員習慣直接在項目中寫死一些定時器。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

我們先看一下一個簡單的示例:

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

這樣做的好處就是友善,調試的時候修改一下定時@Scheduled裡面的時間,然後啟動項目就可以運作,但這樣做的弊端更大,主要有幾個方面:

1、固定的定時任務觸發時間,一旦需要修改執行時間,線上的代碼需要替換安裝包或者打更新檔

2、當服務需要進行多節點部署時,無法控制多個節點的同時執行,可能會重複執行導緻資料混亂,因為 @Scheduled 是 spring 自帶的注解,預設是單線程的,多節點叢集部署的服務,需要加分布式鎖來控制,或者直接用分布式定時任務 Elastic-Job 或者 XXL-JOB 等。

抛開一些小型的項目不說,很多企業為了系統的穩定性和高并發,都會選擇叢集部署,那就需要避開這些問題,今天我們就介紹一個開源項目中比較常用的定時任務技術Quartz。

一、Quartz的認識

解釋:Quartz 是一個開源的作業排程架構,它完全由 Java 寫成,并設計用于 J2SE 和 J2EE 應用中。它提供了巨大的靈活性而不犧牲簡單性。你能夠用它來為執行一個作業而建立簡單的或複雜的排程。它有很多特征,如:資料庫支援,叢集,插件,EJB 作業預建構,JavaMail 及其它,支援 cron-like 表達式等等。

從這句話我們可以看出來,Quartz滿足我們前面說到的要求,它既能實作叢集又支援動态設定cron表達式,友善管理維護。

1、cron表達式

不管是哪種定時技術,我們都需要設定cron表達式,告訴系統我們需要什麼時候執行,那我們就先來了解cron表達式的構成。

cron表達式是用來配置spring定時任務執行時間的字元串,由5個空格分隔成的6個域構成,格式如下:

每一個域的含義解釋:

1) 秒:表示在指定的秒數觸發定時任務,範圍0-59。例如,"*"表示任何秒都觸發,"0,3"表示0秒和3秒觸發。

2) 分:表示在指定的分鐘觸發定時任務,範圍0-59。例如,"0-3"表示0分鐘到3分鐘每分鐘都觸發,"0/2"表示隻有偶數分鐘觸發。

3) 時:表示在指定的小時觸發定時任務,範圍0-23。例如,"3-15/2"表示上午3點到下午3點每隔2個小時觸發。

4) 日:表示在指定的日期觸發定時任務,範圍1-31(可以寫0,但不會生效)。例如,"1"表示1号出發,"5,15"表示5号和15号出發。需要注意的是,日期可以寫0,不會報錯但也不會生效。

5) 月:表示在指定的月份觸發定時任務,範圍1-12。例如,"1-4,12"表示1月到4月以及12月觸發。

6) 周:表示在指定的星期觸發定時任務,範圍0-7(0和7都表示周日)。例如,"?"表示一周都觸發,"6,7"表示周六日觸發。

注意,1月到12月可以用對應的英文縮寫JAN-DEC代替,周日到周六可以用對應的英文縮寫SUN-SAT代替。但是,周日的縮寫SUN隻會被替換為0,是以在cron表達式的周域,我們可以寫6-7,卻不能寫SAT-SUN。(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT)

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

特殊字元的含義說明如下:

1) "*":比對該域的任意值,例如在日域上使用"*",則表示每天都觸發該定時任務。

2) "?":隻能在日和周域使用,表示非明确的值,實際作用等同"*",即比對任意值。一般在日和周上會出現一次,當然,如果你對日和周兩個域都使用"?"或者都使用其他值也沒什麼問題。

3) "-":表示範圍,例如在分域上使用5-10表示從5分鐘到10分鐘每分鐘觸發一次。

4) "/":表示起始時間觸發一次,然後每隔固定時間觸發一次。例如,在分鐘域使用"10/2"表示從10分鐘開始每隔2分鐘觸發一次,直到58分鐘。也可以和字元"-"連用,例如在分鐘域使用"10-30/2"表示從10分鐘開始每隔2分鐘觸發一次,直到30分鐘。

5) ",":表示枚舉多個值,這些值之間是"或"的關系。例如,在月份上使用"1-3,10,12"表示1月到3月,10月,12月都觸發。

下面是一些cron表達式和對應的含義:

"0 30 9 ? * *" 每天上午9:30觸發

"0 0/5 14 * * ?" 在每天下午2點到下午2:55期間的每5分鐘觸發

"0 0-5 14 * * ?" 每天下午2點到下午2:05期間的每1分鐘觸發

"0 10,44 14 ? 3 WED" 三月的星期三的下午2:10和2:44觸發

"0 15 10 ? * MON-FRI" 周一至周五的上午10:15觸發

2、quart的組成

Quartz 的核心類有以下三部分:

  • 任務 Job : 需要實作的任務類,實作execute() 方法,執行後完成任務。
  • 觸發器 Trigger : 包括SimpleTrigger 和 CronTrigger。
  • 排程器 Scheduler : 任務排程器,負責基于Trigger觸發器,來執行 Job任務。

主要關系如下:

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

3、quart涉及的表

資料庫使用quart定時任務,會使用到一些指定的表結構,主要是QRTZ開頭的表結構。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

二、Quartz的內建

1、我們以 SpringBoot 為例,搭建一個純 maven 項目,先添加quartz的依賴:

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

2、按照上圖中的 quartz 主要關系圖,我們先去建立一個自定義的Job,實作 org.quartz.Job 接口,并實作 execute 方法:

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

或者也可以繼承QuartzJobBean類,這種方式需要在maven中額外添加依賴spring-context-support。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

3、我們看一下一個簡單的完整示例(不涉及資料庫的互動和界面的操作,友善大家先從簡單地開始了解掌握):

(1)編寫自定義MyJob,實作Job類,并實作execute方法,在execute方法裡面擷取jobDataMap裝載的可序列化的對象。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

(2)編寫配置類QuartzManager,實作定時任務的實時查詢、修改、新增、删除功能。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

(3)編寫控制類QuartzController,來模拟web端的接口調用。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

這裡面用到了AjaxResult,是我自定義的一個響應類,完全可以自己定義,主要定義code、msg、data等,以及對應的狀态類型(SUCCESS、WARN、ERROR)

(4)編寫完上面3個檔案,我們就可以啟動項目,使用postman來驗證一下了,先模拟調用擷取所有的定時任務,剛開始沒有添加過任何任務,是以會傳回沒有可執行的job,同時控制台輸出對應的日志。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

然後我們模拟調用新增任務,建立一條任務bianchengxia

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

再擷取所有的定時任務,此時出現一條之前建立的任務bianchengxia。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

同理删除也是一樣的邏輯,删除之後再次查詢清單,已經不展示删除的資料了,這裡不再展開。

4、上面的例子是比較簡單的示例,往往我們項目中的實際運用是比較複雜的,需要與資料庫進行互動(就是與quart涉及的表相關),同時在前端web界面上可以進行展示和動态配置,并且記錄操作的日志,我們來看一個示例。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

新增或者修改定時任務的規則:設定定時任務調用方法、執行的時間規則(cron表達式)、執行的政策、是否并發執行已經狀态等核心參數。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

記錄任務的執行日志:

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

以上是web端的界面操作,背景SpringBoot內建這塊,建議把quartz定時器做成一個單獨的子產品,整合到開發的項目當中。我們到配置檔案 application.yml 中配置quartz,也可以單獨寫配置檔案 quartz.properties 然後項目啟動時加載該配置檔案:

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

整體的業務實作,包含工具類(比如校驗cron表達式、擷取上下文資訊、常量、定時任務工具類等)、異常處理類、實體類、接口層和接口實作層、dao層和mybatis資料庫互動層、頁面操作等:

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

核心代碼就是業務實作層,我們看一個核心的SysJobServiceImpl。

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

在看一個定時任務工具類:

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

頁面控制:

Quartz 作業排程架構的掌握,從基礎的純服務到界面可配置化

梳理了之後,我們發現他的核心業務也比較簡單,先建立一個scheduler,然後建立一個Trigger,再建立一個job,最後注冊trigger并啟動scheduler,通過頁面來進行控制,背景進行一些基礎的檢驗,業務實作,實作資料庫互動。

繼續閱讀