【Quartz】深入Job、JobDetail、JobDataMap、Trigger
前些天發(fā)現(xiàn)了一個巨牛的人工智能學(xué)習(xí)網(wǎng)站,通俗易懂,風(fēng)趣幽默,忍不住分享一下給大家。點擊跳轉(zhuǎn)到教程。
Quartz API核心接口有:
- Scheduler – 與scheduler交互的主要API;
- Job – 你通過scheduler執(zhí)行任務(wù),你的任務(wù)類需要實現(xiàn)的接口;
- JobDetail – 定義Job的實例;
- Trigger – 觸發(fā)Job的執(zhí)行;
- JobBuilder – 定義和創(chuàng)建JobDetail實例的接口;
- TriggerBuilder – 定義和創(chuàng)建Trigger實例的接口;
- ?
本文工程免費下載
一、Job
?
??????? 在上一節(jié)中,Job中定義了實際的業(yè)務(wù)邏輯,而JobDetail包含Job相關(guān)的配置信息。在Quartz中,每次Scheduler執(zhí)行Job時,在調(diào)用其execute()方法之前,它需要先根據(jù)JobDetail提供的Job類型創(chuàng)建一個Job class的實例,在任務(wù)執(zhí)行完以后,Job class的實例會被丟棄,Jvm的垃圾回收器會將它們回收。因此編寫Job的具體實現(xiàn)時,需要注意:
(1) 它必須具有一個無參數(shù)的構(gòu)造函數(shù);
(2) 它不應(yīng)該有靜態(tài)數(shù)據(jù)類型,因為每次Job執(zhí)行完以后便被回收,因此在多次執(zhí)行時靜態(tài)數(shù)據(jù)沒法被維護(hù)。
??????? 在JobDetail中有這么一個成員JobDataMap,JobDataMap是Java Map接口的具體實現(xiàn),并添加了一些便利的方法用于存儲與讀取原生類型數(shù)據(jù),里面包含了當(dāng)Job實例運行時,你希望提供給它的所有數(shù)據(jù)對象。
???????? 可以借助JobDataMap為Job實例提供屬性/配置,可以通過它來追蹤Job的執(zhí)行狀態(tài)等等。對于第一種情況,可以在創(chuàng)建Job時,添加JobDataMap數(shù)據(jù),在Job的execute()中獲取數(shù)據(jù),第二種,則可以在Listener中通過獲取JobDataMap中存儲的狀態(tài)數(shù)據(jù)追蹤Job的執(zhí)行狀態(tài)。
一個實現(xiàn)了Job接口的Java類就能夠被調(diào)度器執(zhí)行。接口如下:
?
??????? 很簡的,當(dāng)Job的trigger觸發(fā)時,Job的execute(..)方法就會被調(diào)度器調(diào)用。被傳遞到這個方法里來的JobExecutionContext對象提供了帶有job運行時的信息:執(zhí)行它的調(diào)度器句柄、觸發(fā)它的觸發(fā)器句柄、job的JobDetail對象和一些其他的項。JobDetail對象是Job在被加到調(diào)度器里時所創(chuàng)建的,它包含有很多的Job屬性設(shè)置,和JobDataMap一樣,可以用來存儲job實例時的一些狀態(tài)信息。
?
比如如下任務(wù)類
?
?
?
[java]?view plain?copy?
??????? 當(dāng) Scheduler 調(diào)用一個 Job,一個 JobexecutionContext 傳遞給 execute() 方法。JobExecutionContext 對象讓 Job 能訪問 Quartz 運行時候環(huán)境和 Job 本身的明細(xì)數(shù)據(jù)。這就類似于在 Java Web 應(yīng)用中的 servlet 訪問 ServletContext 那樣。通過 JobExecutionContext,Job 可訪問到所處環(huán)境的所有信息,包括注冊到 Scheduler 上與該 Job 相關(guān)聯(lián)的 JobDetail 和 Triiger。
?
?
?
?
二、JobDetail?
?
JobDetail實例是通過JobBuilder類創(chuàng)建的
可以通過導(dǎo)入該類下的所有靜態(tài)方法
import static org.quartz.JobBuilder.*;然后是創(chuàng)建:
如果不導(dǎo)入靜態(tài)包:
那么就要用:
?
對于部署在 Scheduler 上的每一個 Job 只創(chuàng)建了一個 JobDetail 實例。JobDetail 是作為 Job 實例進(jìn)行定義的。注意到在代碼 中不是把 Job 對象注冊到 Scheduler;實際注冊的是一個 JobDetail 實例。
?
結(jié)果:
?
從上面的代碼中可以看JobDetail 被加到 Scheduler 中了,而不是 job。Job 類是作為 JobDetail 的一部份,但是它直到 Scheduler 準(zhǔn)備要執(zhí)行它的時候才會被實例化的。
?
| 直到執(zhí)行時才會創(chuàng)建 Job 實例? Job 的實例要到該執(zhí)行它們的時候才會實例化出來。每次 Job 被執(zhí)行,一個新的 Job 實例會被創(chuàng)建。其中暗含的意思就是你的 Job 不必?fù)?dān)心線程安全性,因為同一時刻僅有一個線程去執(zhí)行給定 Job 類的實例,甚至是并發(fā)執(zhí)行同一 Job 也是如此。 |
?
?
?
?????? 可以看到,我們傳給scheduler一個JobDetail實例,因為我們在創(chuàng)建JobDetail時,將要執(zhí)行的job的類名傳給了JobDetail,所以scheduler就知道了要執(zhí)行何種類型的job;每次當(dāng)scheduler執(zhí)行job時,在調(diào)用其execute(…)方法之前會創(chuàng)建該類的一個新的實例;執(zhí)行完畢,對該實例的引用就被丟棄了,實例會被垃圾回收;這種執(zhí)行策略帶來的一個后果是,job必須有一個無參的構(gòu)造函數(shù)(當(dāng)使用默認(rèn)的JobFactory時);另一個后果是,在job類中,不應(yīng)該定義有狀態(tài)的數(shù)據(jù)屬性,因為在job的多次執(zhí)行中,這些屬性的值不會保留。
??????? 那么如何給job實例增加屬性或配置呢?如何在job的多次執(zhí)行中,跟蹤job的狀態(tài)呢?答案就是:JobDataMap,JobDetail對象的一部分。
?
三、JobDataMap
???????? JobDataMap中可以包含不限量的(序列化的)數(shù)據(jù)對象,在job實例執(zhí)行的時候,可以使用其中的數(shù)據(jù);JobDataMap是Java Map接口的一個實現(xiàn),額外增加了一些便于存取基本類型的數(shù)據(jù)的方法。
將job加入到scheduler之前,在構(gòu)建JobDetail時,可以將數(shù)據(jù)放入JobDataMap,如下示例:
?
?
?
在job的執(zhí)行過程中,可以從JobDataMap中取出數(shù)據(jù),如下示例:
?
結(jié)果:
?
?
四、 Trigger
??????? Trigger對象是用來觸發(fā)執(zhí)行Job的。當(dāng)調(diào)度一個job時,我們實例一個觸發(fā)器然后調(diào)整它的屬性來滿足job執(zhí)行的條件。觸發(fā)器也有一個和它相關(guān)的JobDataMap,它是用來給被觸發(fā)器觸發(fā)的job傳參數(shù)的。Quartz有一些不同的觸發(fā)器類型,不過,用得最多的是SimpleTrigger和CronTrigger。
??????? 如果我們需要在給定時刻執(zhí)行一次job或者在給定時刻觸發(fā)job隨后間斷一定時間不停的執(zhí)行的話,SimpleTrigger是個簡單的解決辦法;如果我們想基于類似日歷調(diào)度的觸發(fā)job的話,比如說,在每個星期五的中午或者在每個月第10天的10:15觸發(fā)job時,CronTrigger是很有用的。
???????? 為什么用jobs和triggers呢?很多任務(wù)調(diào)度器并沒有任務(wù)和觸發(fā)器的概念,一些任務(wù)調(diào)度器簡單定義一個“job”為在一個執(zhí)行時間伴隨一些小任務(wù)標(biāo)示,其他的更像Quartz里job和trigger對象的聯(lián)合體。在開發(fā)Quartz時,開發(fā)者們決定,在調(diào)度時間表和在這上面運行的工作應(yīng)該分開。這是很有用的。
??????? 例如,job能夠獨立于觸發(fā)器被創(chuàng)建和儲存在任務(wù)調(diào)度器里,并且,很多的觸發(fā)器能夠與同一個job關(guān)聯(lián)起來。這個松耦合的另一個好處就是在與jobs關(guān)聯(lián)的觸發(fā)器終止后,我們能夠再次配置保留在調(diào)度器里的jobs,這樣的話,我們能夠再次調(diào)度這些jobs而不需要重新定義他們。我們也可以在不重新定義一個關(guān)聯(lián)到j(luò)ob的觸發(fā)器的情況下,修改或替代它。
???????? 當(dāng)Jobs和triggers被注冊到Quartz的調(diào)度器里時,他們就有了唯一標(biāo)示符。他們也可以被放到“groups”里,Groups是用來組織分類jobs和triggers的,以便今后的維護(hù)。在一個組里的job和trigger的名字必須是唯一的,換句話說,一個job和trigger的全名為他們的名字加上組名。如果把組名置為”null”,系統(tǒng)會自動給它置為Scheduler.DEFAULT_GROUP
?
Scheduler在使用之前需要實例化。一般通過SchedulerFactory來創(chuàng)建一個實例。有些用戶將factory的實例保存在JNDI中,但直接初始化,然后使用該實例也許更簡單(見下面的示例)。
scheduler實例化后,可以啟動(start)、暫停(stand-by)、停止(shutdown)。注意:scheduler被停止后,除非重新實例化,否則不能重新啟動;只有當(dāng)scheduler啟動后,即使處于暫停狀態(tài)也不行,trigger才會被觸發(fā)(job才會被執(zhí)行)。
?
五、SimpleTrigger的介紹
正如其名所示,SimpleTrigger對于設(shè)置和使用是最為簡單的一種 QuartzTrigger。它是為那種需要在特定的日期/時間啟動,且以一個可能的間隔時間重復(fù)執(zhí)行 n 次的 Job 所設(shè)計的。
我們前面已經(jīng)在一個簡單的Quartz的例子里使用過了SimpleTrigger,我們通過
或者無限執(zhí)行
?
?
對于Quartz而言,它還不能滿足我們的觸發(fā)情況,所以它僅僅是用于一些簡單的觸發(fā)情況;
?
?
?
六、CronTrigger
??????? CronTrigger 允許設(shè)定非常復(fù)雜的觸發(fā)時間表。然而有時也許不得不使用兩個或多個 SimpleTrigger來滿足你的觸發(fā)需求,這時候,你僅僅需要一個 CronTrigger 實例就夠了。顧名思義,CronTrigger 是基于 Unix類似于 cron 的表達(dá)式。例如,你也許有一個 Job,要它在星期一和星期五的上午 8:00-9:00間每五分鐘執(zhí)行一次。假如你試圖用 SimpleTrigger 來實現(xiàn),你或許要為這個 Job 配置多個Trigger。然而,你可以使用如下的表達(dá)式來產(chǎn)生一個遵照這個時間表觸發(fā)的 Trigger;
比如:
?
?
?
?
??????? 因為 CronTrigger內(nèi)建的如此強(qiáng)的靈活性,也與生俱來可用于創(chuàng)建幾乎無所限制的表達(dá)式,且因為支持unix的cron表達(dá)式,則做為企業(yè)應(yīng)用,我們的操作系統(tǒng)一般也都以unxi操作系統(tǒng)為主,所以掌握CronTrigger的使用費用有必要,我們將在后面對CronTrigger 進(jìn)行詳細(xì)的介紹。cron 表達(dá)式的格式見下一節(jié)。
七、Job與Trigger的關(guān)系
??????? 大家都知道,一個作業(yè),比較重要的三個要素就是Schduler,jobDetail,Trigger;而Trigger對于job而言就好比一個驅(qū)動器;沒有觸發(fā)器來定時驅(qū)動作業(yè),作業(yè)就無法運行;對于Job而言,一個job可以對應(yīng)多個Trigger,但對于Trigger而言,一個Trigger只能對應(yīng)一個job;所以一個Trigger 只能被指派給一個 Job;如果你需要一個更復(fù)雜的觸發(fā)計劃,你可以創(chuàng)建多個 Trigger 并指派它們給同一個 Job。Scheduler 是基于配置在 Job上的 Trigger 來決定正確的執(zhí)行計劃的,下面就是為同一個 JobDetail 使用多個Trigger;
?
轉(zhuǎn)自:http://blog.csdn.net/evankaka
本文工程免費下載
總結(jié)
以上是生活随笔為你收集整理的【Quartz】深入Job、JobDetail、JobDataMap、Trigger的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MFC消息详解 (WindowProc|
- 下一篇: C#winform使用进度条