02 Quartz-初識Quartz-組件解釋

02 Quartz-初識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í)行)。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容