天天看點

Quartz任務排程(1)概念例析快速入門Quartz架構需求引入執行個體解析概念具體用法詳解

1. 允許我們靈活而細粒度地設定任務觸發時間,比如常見的每隔多長時間,或每天特定時刻、特定日子(如節假日),都能靈活地配置這些成相應時間點來觸發我們的任務

2. 提供了排程環境的持久化機制,可以将任務内容儲存到資料庫中,在完成後删除記錄,這樣就能避免因系統故障而任務尚未執行且不再執行的問題。

在quartz中,有幾個核心類和接口:job、jobdetail、trigger、calendar、scheduler。

下面我們結合執行個體來分析這些類的角色定位。

現在我們有一個新聞網站,它有一張任務日志表,記錄着我們的不同任務,比如每隔三十分鐘要根據文章的閱讀量和評論量來生成我們的最熱文章清單。在每天早晚12點,定時從其他新聞網站扒取一定量新聞,在每周一晚上12點到3點進行論壇封閉維護,而如果遇到節假日則不維護等。在以上執行個體中:

生成最熱文章,扒取新聞,論壇封閉維護都是我們的job,它定義了我們的需要執行的任務,是一個抽象的接口. 如果我們要具體到每隔三十分鐘生成最熱文章,早晚12點扒取新聞等,在我們的具體任務執行時刻,我們就需要能夠描述job及其他相關靜态資訊的jobdetail,它相當于是我們的job+具體實作細節 而trigger則描述了job執行的時間觸發規則,比如每隔三十分鐘、早晚12點等 而這裡的calendar可以看成是一些月曆特定時間點的集合,比如我們這裡遇到節假日則不維護,節假日如國慶節、愚人節等等,都是我們的月曆特定時間點。 而scheduler就是我們的任務日志表,它是一個容器,記載(容納)了我們前面的工作、觸發時間等内容。

通過執行個體,我們對quartz的核心類有了較清晰的功能定位,根據quratz的不同版本,這幾個核心類有較大改動,具體的操作不太相同,但是思路是相同的;比如1.+版本jar包中,jobdetail是個類,直接通過構造方法與job類關聯。simpletrigger和corntrigger是類;在2.+jar包中,jobdetail是個接口,simpletrigger和corntrigger是接口。下面詳細地分析它們的具體用法:

job是一個接口,隻有一個void execute(jobexecutioncontext jec)方法,jobexecutioncontext提供了我們的任務排程上下文資訊,比如,我們可以通過jobexecutioncontext擷取job相對應的jobdetail、trigger等資訊,我們在配置自己的内容時,需要實作此類,并在execute中重寫我們的任務内容。下面是我們的扒取新聞工作執行個體:

quartz在每次執行任務時,都會建立一個job執行個體,并為其配置上下文資訊,jobdetail有一個成員屬性jobdatamap,存放了我們job運作時的具體資訊,在後面我們會詳細提到。

1. 在1.+版本中,它作為一個類,常用的構造方法有:jobdetail(string name, string group, class jobclass),我們需要指定job的名稱,組别和實作了job接口的自定義任務類。執行個體如<code>jobdetail jobdetail =new jobdetail("job1", "jgroup1", picknewsjob.class);</code>

2. 而在2.+版本中,我們則通過一下方法建立 <code>jobbuilder.newjob(自定義任務類).withidentity(任務名稱,組名).build();執行個體如</code>jobdetail jobdetail = jobbuilder.newjob(picknewsjob.class).withidentity(“job1”,”group1”).build();`

先講scheduler,友善後講解trigger時測試。

scheduler作為我們的“任務記錄表”,裡面(可以)配置大量的trigger和jobdetail,兩者在 scheduler中擁有各自的組及名稱,組及名稱是scheduler查找定位容器中某一對象的依據,trigger的組及名稱必須唯一,jobdetail的組和名稱也必須唯一(但可以和trigger的組和名稱相同,因為它們是不同類型的)。scheduler可以将trigger綁定到某一jobdetail中,這樣當trigger觸發時,對應的job就被執行。一個job可以對應多個trigger,但一個trigger隻能對應一個job。可以通過schedulerfactory建立一個scheduler執行個體。下面是使用schduler的執行個體:

在一個scheduler被建立後,它處于”stand-by”模式,在觸發任何job前需要使用它的start()方法來啟動。同樣的,如果我們想根據我們的業務邏輯來停止定時方案執行,可以使用scheduler.standby()方法

trigger描述了job執行的時間觸發規則,主要有simpletrigger和crontrigger兩個子類。

如果嵌入事件機制隻觸發一次,或意圖使job以固定時間間隔觸發,則使用simpletrigger較合适,它有多個構造函數,其中一個最複雜的構造函數為:

<code>simpletrigger(string name, string group, string jobname, string jobgroup, date starttime, date endtime, int repeatcount, long repeatinterval)</code>參數依次為觸發器名稱、觸發器所在組名、工作名、工作所在組名、開始日期、結束日期、重複次數、重複間隔。

1. 如果我們不需同時設定這麼多屬性,可調用其他隻有部分參數的構造方法,其他參數也可以通過set方法動态設定。

2. 這裡需要注意的是,如果到了我們設定的endtime,即時重複次數repeatcount還沒有達到我們預設定的次數。任務也不會再此執行。

下面是1.+版本的建立執行個體

下面是2.+版本的建立執行個體

通過triggerbuilder,我們可以通過方法友善地配置觸發器的各種參數。

通過cron表達式定義複雜的時間排程方案,具體内容我們在下一篇詳細提到

在實際的開發中,我們可能需要根據節假日來調整我們的任務排程方案。執行個體如下:

在這裡,除了可以使用annualcalendar外,還有croncalendar(表達式),dailycalendar(指定的時間範圍内的每一天),holidaycalendar(排除節假日),monthlycalendar(排除月份中的數天),weeklycalendar(排除星期中的一天或多天)

至此,我們的核心類基本講解完畢,下面附上我們的完整測試代碼:

可見,兩個不同版本的主要差別在于jobdetail和triiger的配置。

此外,除了使用<code>scheduler.schedulejob(jobdetail, simpletrigger)</code>來建立jobdetail和simpletrigger的關聯外,在1.+版本中的配置還可以采用如下所示方式

這裡還需要注意的是,如果我們使用<code>scheduler.addcalendar("holidays", holidays, false, false)</code>必須在向scheduler注冊trigger之前<code>scheduler.schedulejob(simpletrigger)</code>,否則會抛異常:calendar not found: holidays

而在2.+版本中,我嘗試在建立triiger時用forjob(“job1”, “jgroup1”)來綁定job名群組名

//後面是一樣的

scheduler.addjob(jobdetail, true);

scheduler.schedulejob(simpletrigger);

在運作時,卻會抛出異常: jobs added with no trigger must be durable.

顯然是綁定失敗了,目前暫未找到解決方法,如果有找到解決方法的朋友,懇請告訴我一下,十分感謝!