JobDetail實例,并且,它通過job的類代碼引用這個job來執行。每次調度器執行job時,它會在調用job的execute(..)方法之前創建一個他的實例。這就帶來了兩個事實:一、job必須有一個不帶參數的構造器,二、在job類里定義數據成員并沒有意義,因為在每次job執行的時候他們的值會被覆蓋掉。
你可能現在想要問“我怎樣給一個job實例提供屬性/配置?”和“在幾次執行間我怎樣能跟蹤job的狀態?”這些問題的答案是一樣的:用JobDataMap- JobDetail對象的一部分。
JobDataMap
JobDataMap能夠支持任何序列化的對象,當job執行時,這些對象能夠在job實例中可用。JobDataMap實現了Java Map接口,它有一些附加的方法,這些方法用來儲存和跟蹤簡單類型的數據。
如下代碼可以很快地給job增加JobDataMap:
jobDetail.getJobDataMap().put("jobSays", "Hello World!");
jobDetail.getJobDataMap().put("myFloatValue", 3.141f);
jobDetail.getJobDataMap().put("myStateData", new ArrayList());
在job執行時,我們可以在job里通過如下代碼得到JobDataMap:
public class DumbJob implements Job {
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
String instName = context.getJobDetail().getName();
String instGroup = context.getJobDetail().getGroup();
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
ArrayList state = (ArrayList)dataMap.get("myStateData");
state.add(new Date());
System.err.println("Instance " + instName + " of DumbJob says: " + jobSays);
}
}
如果用一個持久JobStore(在指南JobStore章節討論),我們就應該注意在JobDataMap里放些什么,因為在它里面的對象將會被序列化,并且這些對象會因此產生一些class-versioning問題。明顯的,標準Java類型應該是很安全的,但是,任何時候某人改變了一個你已經序列化的實例的類的定義時,我們就要注意不能夠破壞兼容性了。在這個方面的進一步信息可以在Java Developer Connection Tech Tip: Serialization In The Real World里找到。我們能把JDBC-JobStore和JobDataMap放到一個模式里,在那里,只有簡單類型和String型能被儲存在Map里,從而消去任何以后的序列化問題。
Stateful vs. Non-Stateful Jobs
觸發器也有與它們關聯的JobDataMaps。假設我們有一個儲存在調度器里被多個觸發器關聯的job,然而,對于每個獨立的觸發器,我想提供給job不同的數據輸入,在這個時候,JobDataMaps就很有用了。
在job執行期間,JobDataMaps能夠在JobExecutionContext里獲得。JobDataMap融合在Trigger和JobDetail類里,JobDataMap里面的值能夠利用key來更新。
以下例子顯示,在job執行期間從JobExecutionContext里的JobDataMap得到數據:
public class DumbJob implements Job {
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
String instName = context.getJobDetail().getName();
String instGroup = context.getJobDetail().getGroup();
JobDataMap dataMap = context.getJobDataMap(); // 注意:不同于以前的例子
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
ArrayList state = (ArrayList)dataMap.get("myStateData");
state.add(new Date());
System.err.println("Instance " + instName + " of DumbJob says: " + jobSays);
}
}
StatefulJob
現在,關于job狀態數據的一些附加要點:一個job實例能定義為"有狀態的"或者"無狀態的"。無狀態的jobs僅當它們在被加入到調度器里時才存儲JobDataMap。這就意味著,在jobs執行期間對JobDataMap里數據的任何改變都會丟失,下次執行時job將看不到這些數據。你可能會猜到,一個有狀態的job就是它的反面例子-它的JobDataMap是在每次執行完job后再次儲存的。一個缺點就是有狀態的job不能夠并發執行。換句話說,如果job是有狀態的,一個觸發器嘗試觸發這個已經執行了的job時,這個觸發器就會等待直到這次執行結束。
用實現
Job 'Instances'
我們能夠創建一個單獨的job類,并且通過創建多個JobDetails實例在調度器里儲存很多它的“實例定義”,每個都有它自己的屬性集和JobDataMap ,把它們都加入到調度器里。
當一個觸發器觸發時,與它關聯的job就是通過配置在調度器上的JobFactory 來實例化的。默認的JobFactory 簡單的調用在job類上的newInstance()方法,你可能想要創建自己的JobFactory實現來完成一些自己想要的事情,如:擁有應用程序的IoC或者DI容器進程/初始化job實例。
job的其他屬性
這兒有一個其他屬性的總結,這些屬性是通過JobDetail對象為一個job實例定義的。
- 持久性– 如果一個job是非持久的,一旦沒有任何可用的觸發器與它關聯時,他就會自動得從調度器里被刪除。
- 不穩定性-如果一個job是不穩定的,他就不會在重起Quartz調度器之間持久化。
- 請求恢復– 如果一個job“請求恢復”,在調度器“硬關閉”(如:該進程崩潰,機器被關掉)時這個job還在執行,過后,當調度器再次啟動時,他就會再次執行。在這種情況下,JobExecutionContext.isRecovering() 方法將會返回true.
- Job監聽器 –一個job能夠有0個或者多個與它關聯的監聽器。當job執行時,監聽器就會被通知。在監聽器的更多討論請看TriggerListeners & JobListeners
JobExecutionException
最后,我們來看看Job.execute(..)方法的一些細節。你能夠從execute方法里拋出的僅有的異常類型就是JobExecutionException。因為這樣,我們應該使用try-catch塊包圍整個execute方法內容。我們還應該花一些時間看看JobExecutionException文檔。當job執行發生異常時,通過設置JobExecutionException,可以讓此job再次進入調度器或者今后不再運行。