原文地址: http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/tutorials/tutorial-lesson-03.htmlhtml
第三課: Jobs 與 Job Details 更多相關編程
正如你在第二課所見,任務實現起來至關簡單,僅僅有一個 'execute' 方法在接口。這裏僅有少數東西你須要明白關於jobs的本質,關於Job 接口 execute(...) 方法,還有 JobDetails。安全
當你實現一個任務類,有知道如何作特定類型工做的代碼,Quartz 須要瞭解關於各類你但願任務實例擁有的屬性。這個就經過JobDetail完成,在上一節已經簡單提過。併發
JobDetail 實例是經過 JobBuilder 類構建的。你一般能夠用一個靜態導入所有它的方法,爲了讓你的代碼看起來有領域規範語言的感受。less
import static org.quartz.JobBuilder.*;複製代碼
讓咱們花一點時間討論一點 Jobs的本性和 job實例的在Quartz的生命週期。首先讓咱們回頭看一眼咱們在第一課的代碼片斷:ui
// 定義任務並綁定咱們的 HelloJob 類
JobDetail job = newJob(HelloJob.class)
.withIdentity("myJob", "group1") // name "myJob", group "group1"
.build();
// 觸發任務馬上運行,而且妹40秒有也行
Trigger trigger = newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(40)
.repeatForever())
.build();
// 告訴 quartz 執行調度使用的觸發器
sched.scheduleJob(job, trigger);複製代碼
如今考慮任務類 "HelloJob" 定義以下:this
public class HelloJob implements Job {
public HelloJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
System.err.println("Hello! HelloJob is executing.");
}
}複製代碼
注意咱們爲任務調度指定一個JobDetail實例,而且在構建JobDetail時,只需提供做業的類便可執行的做業類型。每一次任務調度執行任務,它會在被調用 execute(...)方法前被建立新的實例。當執行結束,任務類實例的引用被丟棄,而且實例會被回收。這種行爲的一個後果就是任務必要有一個無參構造器(當使用默認的 JobFactoy 實現時)。另外一個結果就是在做業類上定義狀態數據字段是沒有意義的-他們的值不會在任務執行期間被保存。編碼
你可能會想問「我怎樣才能爲一個任務實例保存屬性/配置?」 還有 「我怎樣才能跟蹤一個任務的狀態在執行之間?」他們的答案都是同樣的,關鍵是JobDataMap, JobDetail對象的一部分。spa
JobDataMap 能夠用來持有任意數量(序列化)數據對象那些你在任務實例執時可用的。JobDataMap
是Java Map接口的一個實現,而且加了一些方便的方法用於存儲和恢復原始類型的數據。設計
這裏是關於在定義/構建 JobDetail 存放數據到 JobDataMap
的代碼片斷,在一個任務加入調度任務以前:
// 定義任務而且綁定到DumbJob類
JobDetail job = newJob(DumbJob.class)
.withIdentity("myJob", "group1") // name "myJob", group "group1"
.usingJobData("jobSays", "Hello World!")
.usingJobData("myFloatValue", 3.141f)
.build();複製代碼
如下是一個在任務執行見從JobDataMap
獲取數據的簡單例子:
public class DumbJob implements Job {
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
JobKey key = context.getJobDetail().getKey();
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
}
}複製代碼
若是你想要一個持久化的 任務存儲(在本教程的 JobStore章節討論過) 你應該謹慎決定放在 JobDataMap
的地方,由於對象會被序列化,所以,它們很容易出現類版本控制問題。顯然,標準的Java類型應該是很安全的,但超過這個,任什麼時候候某人改變一個你已經實現的類實例的定義,必須當心不要破壞兼容性。另外一個選擇是,你能夠放 JDBC_JobStore 和 JobDataMap 進入只容許原語和字符串存儲在映射中的模式,從而消除了之後出現序列化問題的可能性。
若是你增長對應於 JobDataMap中鍵名的 setter 方法到你的任務類(好像下面例子的 data 中 setJobSay(String val)) 方法,而後Qurartz 的默認 JobFactory 實例會自動調用他的 setter 在 Job 實例化後,所以,無需在你的execute方法內從映射中顯式獲取值。
觸發器一樣能夠 JodDataMaps關聯。這樣在當你有一個任務被存儲在調度程序中給多個觸發器按期/重複使用的狀況下頗有用,然而,對於每一個獨立的觸發,你都爲任務提供不一樣的數據輸入。
JobDataMap 在任務執行的時候,很方便在JobExeccutionContext找到。它是JobDetail上的JobDataMap和Trigger上的JobDataMap的結合,使用後者中的值覆蓋前者中的任何同名值。
這裏是一個簡短的例子,演示怎樣從 JobExecutionContext 和 JobDataMap的整合從獲取數據,在任務執行時。
public class DumbJob implements Job {
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
JobKey key = context.getJobDetail().getKey();
JobDataMap dataMap = context.getMergedJobDataMap(); // Note the difference from the previous example
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
ArrayList state = (ArrayList)dataMap.get("myStateData");
state.add(new Date());
System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
}
}複製代碼
或者你但願依靠 JobFactory 注入 數據Map值經過你本身類,它看起來會像這樣:
public class DumbJob implements Job {
String jobSays;
float myFloatValue;
ArrayList state;
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
JobKey key = context.getJobDetail().getKey();
JobDataMap dataMap = context.getMergedJobDataMap(); // Note the difference from the previous example
state.add(new Date());
System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
}
public void setJobSays(String jobSays) {
this.jobSays = jobSays;
}
public void setMyFloatValue(float myFloatValue) {
myFloatValue = myFloatValue;
}
public void setState(ArrayList state) {
state = state;
}
}複製代碼
你會注意到整體代碼更長了,單在 execute() 方法裏面的代碼更清晰。有人可能會說,雖然代碼更長,單實際用到了更少的代碼,若是編程的 IDE 有本身建立 setter 方法,而沒必要手動編寫各個調用的代碼來從JobDataMap檢索值。由你選擇。
不少用戶花時間搞不清什麼是任務實例。咱們嘗試在如下的章節裏面說清楚任務狀態和併發性。
你能夠建立一個單獨的任務類,而且存儲多個「實例定義」經過建立JobDetails的多個實例在調度程序中-每一個都有其本身的屬性和JobDataMap-並將它們所有添加到調度程序中。
舉例,你能夠建立一個名字叫 "SalesReportJob"的任務實例。這個任務可能被指望的參數發送(好像 JobDataMap) 到指定銷售報告所依據的銷售人員的姓名。他們可能在任務建立多個定義(JobDetails) ,好像"SalesReportForJbe" 和 "SaleReportForMike" 用"joe" 和 "mike" 在相應的JobDataMaps中指定爲各個做業的輸入。
當一個觸發器點燃,JobDetail(實例定義) 關聯被加載,而且 任務類實例被 JobFactory 引用 配置到 執行調度。默認 JobFactory 調用 job 類的 newInstance() 方法,意圖調用在類上與JobDataMap的鍵名匹配的方法。你可能想建立你本身的 JobFactory 實例去完成你應用的 IOC 或者 DI 容器 生產/初始化任務實例。
在 "Quartz speak" , 咱們說起到每一個存儲的JobDetail 好像 "job definiton" 或 "JobDetail instance" ,而後咱們說起到每個執行的任務好似"job instance" 或者 "instance of a job definition"。一般,若是咱們僅僅使用 「job」這個詞,咱們是說起一個命名定義,或者 JobDetail。當咱們說起到 job 類實例,咱們一般用術語 "job class"。
如今,一些關於任務狀態數據(也就是 JobDataMap)和並行)的附加說明。這裏是有一對註解能夠在加在你的任務類上,影響 Quzrtz 的行爲。
@DisallowConcurrentExecution 是一個能夠加在任務類上的註解,告訴 Quartz不能夠在指定的任務定義(這裏指指定的任務類)並行執行多個實例。注意這裏的用詞,是很是謹慎選擇的。在上一節的例子,若是 "SalesReportJob" 有這個註解,那麼僅有一個 "SalesReportForJoe"的實例能夠在指定時間執行,但能夠並行執行一個"SaleReportForMike"的實例。約束是基於實例定義(JobDetail),不是在任務的實例。然而,它是取決於(在Quartz設計期間)註解是否對自己進行了處理,由於它常常對類的編碼方式產生影響。
@PersistJobDataAfterExecution 是一個能夠加在任務類上的註解,告訴Quzrtz 在執行 execute() 方法成功後(沒有拋出異常)更新JobDetail的 JobDataMap存儲,這樣下一次執行一樣的任務(JobDetail) 接收到更新值而不是存儲的值好像@DisallowConcurrentExcetion 同樣,適用於一個任務的實例,不是一個任務類是實例,取決於任務類的屬性由於它一般對類的編碼方式產生影響。(好像"statefulness" 會須要明確的"understood"經過在execute 方法裏的代碼)。
若是你用@PersistJobDataAfterExecution 這個註解,你須要慎重考慮同時用@DisallowConcurrentExecution 註解,爲了不一個相同的任務(JobDetail)並行時存儲的數據致使可能的混亂(速度混亂)。
這裏是一個快速總結定義一個任務實例即 JobDetail 對象的其餘屬性:
最後,咱們須要告知你 Job.execute(...)
的一些細節。惟一的一種異常類型(包含RuntimeEcxeption) 你能夠從執行方法中拋出的異常是 JobExecutionException。 正是由於這樣,你應該一般包裝所有內容在「try-catch」塊中。你還應該花點時間閱讀文檔中,關於JobExecutionExcetion的部分,爲調度程序提供各類指令,以肯定您但願如何處理異常。
本文由博客一文多發平臺 OpenWrite 發佈!