02 Quartz-初識Quartz-組件

01 Quartz-初識Quartz-樣例入手 實現(xiàn)了一個簡單運行demo. 正常情況下也能運行起來,進行日志輸出!
本篇根據(jù)這個demo 對其一些組件進行一個解釋析!
Quartz 名詞定義
1. Job
Quartz中的Job是什么?
Job - 由希望由調(diào)度程序執(zhí)行的組件實現(xiàn)的接口。
所以實在開發(fā)中我們需要實現(xiàn)Job 接口,重寫 void execute(JobExecutionContext context) 方法。
package org.quartz;
public interface Job {
public void execute(JobExecutionContext context)
throws JobExecutionException;
}
Job使用邏輯:我們只需創(chuàng)建一個job類,然后創(chuàng)建多個與該job關聯(lián)的JobDetail實例,每一個實例都有自己的屬性集和JobDataMap,最后,將所有的實例都加到scheduler中。當一個trigger被觸發(fā)時,與之關聯(lián)的JobDetail實例會被加載,JobDetail引用的job類通過配置在Scheduler上的JobFactory進行初始化。默認的JobFactory實現(xiàn),僅僅是調(diào)用job類的newInstance()方法,然后嘗試調(diào)用JobDataMap中的key的setter方法。你也可以創(chuàng)建自己的JobFactory實現(xiàn),比如讓你的IOC或DI容器可以創(chuàng)建/初始化job實例。
Job的并發(fā)說明:@DisallowConcurrentExecution:將該注解加到job類上,告訴Quartz不要并發(fā)地執(zhí)行同一個job定義(這里指特定的job類)的多個實例。所以該限制是針對JobDetail的,而不是job類的。但是我們認為(在設計Quartz的時候)應該將該注解放在job類上,因為job類的改變經(jīng)常會導致其行為發(fā)生變化。
Job狀態(tài): @PersistJobDataAfterExecution:將該注解加在job類上,告訴Quartz在成功執(zhí)行了job類的execute方法后(沒有發(fā)生任何異常),更新JobDetail中JobDataMap的數(shù)據(jù),使得該job(即JobDetail)在下一次執(zhí)行的時候,JobDataMap中是更新后的數(shù)據(jù),而不是更新前的舊數(shù)據(jù)。和 @DisallowConcurrentExecution注解一樣,盡管注解是加在job類上的,但其限制作用是針對job實例的,而不是job類的。由job類來承載注解,是因為job類的內(nèi)容經(jīng)常會影響其行為狀態(tài)(比如,job類的execute方法需要顯式地“理解”其”狀態(tài)“)。
...其他特性參考:
2. JobDetail
Quartz中的JobDetail是什么?
通過對Job的理解,我們知道非常容易實現(xiàn),只需要實現(xiàn)Job 接口,重寫execute方法。這樣我們就實現(xiàn)了一個Job接口的類,但是呢這個類的功能其實我們也知道它僅僅是完成某個功能/任務,除此之外:Quartz還需要知道該Job實例所包含的屬性;這將由JobDetail類來完成。
JobDetail - 用于定義作業(yè)的實例,JobDetail實例是通過JobBuilder類創(chuàng)建的。它包含job的各種屬性設置,以及用于存儲job實例狀態(tài)信息的JobDataMap。
JobDetail對象是在將job加入scheduler時,由客戶端程序(你的程序)顯示創(chuàng)建的??聪旅娲a片段:
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroup).build();
...
scheduler.scheduleJob(jobDetail, trigger);
我們傳給scheduler一個JobDetail實例,因為我們在創(chuàng)建JobDetail時,將要執(zhí)行的job的類名傳給了JobDetail,所以scheduler就知道了要執(zhí)行何種類型的job;每次當scheduler執(zhí)行job時,在調(diào)用其execute(…)方法之前會創(chuàng)建該類的一個新的實例;執(zhí)行完畢,對該實例的引用就被丟棄了,實例會被垃圾回收;這種執(zhí)行策略帶來的一個后果是,job必須有一個無參的構造函數(shù)(當使用默認的JobFactory時);另一個后果是,在job類中,不應該定義有狀態(tài)的數(shù)據(jù)屬性,因為在job的多次執(zhí)行中,這些屬性的值不會保留。
JobDataMap (demo中并沒有使用該組件)JobDataMap中可以包含不限量的(序列化的)數(shù)據(jù)對象,在job實例執(zhí)行的時候,可以使用其中的數(shù)據(jù);JobDataMap是Java Map接口的一個實現(xiàn),額外增加了一些便于存取基本類型的數(shù)據(jù)的方法。使用方式如下:
// add data to JobDataMap
JobDetail job = newJob(DumbJob.class)
.withIdentity("myJob", "group1") // name "myJob", group "group1"
.usingJobData("data1", "aaa")
.usingJobData("data2", "bbb")
.build();
//get data from JobDataMap
public class MybJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
JobKey key = context.getJobDetail().getKey();
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String data1 = dataMap.getString("jobSays");
String data2 = dataMap.getFloat("myFloatValue");
System.err.println("data1 " + data1 + ", and data2 is: " + data2);
}
}
3. Trigger
-
Trigger(即觸發(fā)器) - 定義執(zhí)行給定作業(yè)的計劃的組件。
Trigger用于觸發(fā)Job的執(zhí)行。當你準備調(diào)度一個job時,你創(chuàng)建一個Trigger的實例,然后設置調(diào)度相關的屬性。Trigger也有一個相關聯(lián)的JobDataMap,用于給Job傳遞一些觸發(fā)相關的參數(shù)。Quartz自帶了各種不同類型的Trigger,最常用的主要是SimpleTrigger和CronTrigger。SimpleTrigger主要用于一次性執(zhí)行的Job(只在某個特定的時間點執(zhí)行一次),或者Job在特定的時間點執(zhí)行,重復執(zhí)行N次,每次執(zhí)行間隔T個時間單位。
CronTrigger在基于日歷的調(diào)度上非常有用,如“每個星期五的正午”,或者“每月的第十天的上午10:15”等。
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder
.newTrigger()
.withIdentity(jobName, jobGroup);
Trigger trigger = triggerBuilder
.startAt(triggerDate)
.withSchedule(schedBuilder)
.build(); // 將job trigger放入scheduler scheduler.scheduleJob(jobDetail, trigger);
4. Scheduler
- Scheduler - 與調(diào)度程序交互的主要API。
Scheduler的生命期,從SchedulerFactory創(chuàng)建它時開始,到Scheduler調(diào)用shutdown()方法時結束;Scheduler被創(chuàng)建后,可以增加、刪除和列舉Job和Trigger,以及執(zhí)行其它與調(diào)度相關的操作(如暫停Trigger)。但是,Scheduler只有在調(diào)用start()方法后,才會真正地觸發(fā)trigger(即執(zhí)行job),使用Scheduler之前,需要實例化。
public class QuartzScheduler {
/**
* 定義 全局 Scheduler 方便以下方法使用
*/
private static Scheduler scheduler;
/**Scheduler
* 初始化
*/
static {
try {
scheduler = getSechduler();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 獲取Scheduler instance
* 實際生產(chǎn)中不建議這么做:最好采用資源隔離的方式;避免任務過多進行資源搶占導致任務misfire
* @return
* @throws SchedulerException
*/
public static Scheduler getSechduler() throws SchedulerException {
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
if (scheduler == null) {
synchronized (QuartzScheduler.class) {
if (scheduler == null) {
scheduler = schedulerFactory.getScheduler();
}
}
}
return scheduler;
}
}
scheduler實例化后,可以啟動(start)、暫停(stand-by)、停止(shutdown)。
注意:scheduler被停止后,除非重新實例化,否則不能重新啟動;只有當scheduler啟動后,即使處于暫停狀態(tài)也不行,trigger才會被觸發(fā)(job才會被執(zhí)行)。