經過Job,Trigger,Scheduler看Quartz2.x做業調度框架

  最近使用到Quartz框架來作定時推送數據的功能的調度(注:在Java可使用java.util.Timer和實現java.util.TimerTask接口的類作定時任務功能)。html


 本文主要從大的框架方面介紹Quartz的基本使用和Quartz對用戶提供的擴展點JobListener等監聽接口。java


  一般對於做業調度咱們關注這三個方面的內容:做業,調度時間,由誰調度。好比:我明天去北京。這就好中,將「去北京」看作一個做業,「我」就是這個做業的調度者,而「明天」天然就是調度的時間(也能夠看做是去北京這個做業的觸發時間)。spring


  由上面的小情節能夠看出框架能爲咱們作那些事呢?分離通用的,業務無關的部分組織成爲解決某一問題或特定問題的模版代碼即爲框架。正好,Quartz就是做業調度方面或者領域的解決方案框架。再去看「去北京」這個關鍵詞,能夠發現去北京對於實際的業務而言僅僅是一個描述性的語句,而怎麼去(灰機,BBC,仍是綠皮車)好像這些並沒能體現出來,而這樣沒有體現出來的好處就是框架和業務實現徹底解耦。這裏就要引入幾個做業調度方面的專業名詞,好比Job,Trigger ,Scheduler。咱們這一這麼組織這三個名詞,好比:一個Schedule懷揣個Trigger,這個Trigger有個玩叫Job,時不時拿出來玩兩下。至於玩一下Job,Job可以產生怎樣的影響對於Trigger而言並不關心,不過這裏彷佛使得Job與Trigger產生了耦合,由於Job屬於具體業務。對於一個完備的做業調度解決方案Quartz而言這樣的問題已不是問題,Quartz用JobDetail來表示Job或者表達Job,從而讓具備具體業務的Job與整個框架分離。編程


 下面經過Quartz的類圖來宏觀的介紹Quartz2.x的使用。
框架

 1.Job和JobDetail分佈式

 

 wKiom1V_iE2CY3YSAABlY2RCSeE692.jpg

   具體做業業務實現Job接口,具體在做業調度中使用JobDetail,使用JobBuilder構造器來構造具體的JobDetail。兩個接口+一個構造者模式的JobDetail構造器完成了具體業務Job和實際做業調度中的JobDetail分離。實際應用中只要面向JobDetail和Job兩個接口編程,隱藏了具體的實現如:JobDetailImpl類。ide


 2.Triiger(做業觸發器)ui

 對於做業觸發器大多與時間,日期,調度次數,間隔時間,調度延時等有關,Quartz對做業觸發作了分類並提供了TriggerBuilder。this

 wKiom1V_ilWzlX-kAAEpU5lHdXw055.jpg


  從上圖能夠看到Trigger接口下有不一樣的觸發類型,如平常間隔觸發(DailyTimeIntervalTriggerImpl),基於日曆的觸發,Cron出發,簡單的觸發。一樣TriggerBuilder提供了構建Trigger的簡便方式,使用者能夠經過其來設置不一樣的屬性信息構建具體的Trigger實現的實例。spa


 3.做業調度器Scheduler

 

  wKiom1V_i1vhypo0AACajASQALk167.jpg


  Quartz提供了不一樣類型的調度器實現,通常咱們使用StdScheduler便可知足須要,如涉及到分佈式或者遠程方法調用則能夠選擇其它兩種合適的實現。

 

 4.Quartz提供的擴展之Listener

 wKioL1V_jW-iU1iOAAC3Zbho8cc541.jpg

 


  Quartz提供了各類Listener接口爲用戶觀察做業,觸發器,做業調度器執行過程提供了擴展點。

  Scheduler對象具備ListenerManager的屬性,ListenerManager對象用來管理TriggerListener,JobListener,SchedulerListener的實現,監聽關係(好比:指定全局Job監聽,指定特定的Job監聽等),具體使用參見下文。

 

 

  下面提供一組Quartz使用的示例代碼:


package secondriver.springsubway.demo.job;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;


public class TestJobListener {

    public static Scheduler scheduler;

    @BeforeClass
    public static void setBeforeClass() throws SchedulerException {
        StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
        scheduler = schedulerFactory.getScheduler();
        scheduler.start();
    }

    @AfterClass
    public static void setAfterClass() throws SchedulerException {
        if (scheduler.isStarted()) {
            scheduler.shutdown(true);
        }
    }

    //Prepared for Test

    /**
     * 使用Builder模式構建JobDetail實例
     * @return
     */
    public static JobDetail getJobDetail() {
        return JobBuilder.newJob(MyJob.class).withDescription("MyJobDetail")
                .withIdentity("myJob", "myJobGroup")
                .build();
    }

    /**
     * 使用Builder模式構建Trigger實例
     * @return
     */
    public static Trigger getTrigger() {
        return TriggerBuilder.newTrigger().withDescription("MyTrigger").withIdentity("myTrigger",
                "myTriggerGroup")
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3))
                .startNow().build();
    }

    @Test
    public void testOne() throws SchedulerException {
        JobDetail jobDetail = getJobDetail();
        Trigger trigger = getTrigger();

        scheduler.getListenerManager().addJobListener(new MyJobListener());
        scheduler.getListenerManager().addTriggerListener(new MyTriggerListener());

        scheduler.scheduleJob(jobDetail, trigger);

    }

    @Test
    public void testTwo() throws SchedulerException {
        JobDetail jobDetail = getJobDetail();
        Trigger trigger = getTrigger();

        /**
         * 爲指定jobGrup添加JobListener
         */
        scheduler.getListenerManager().addJobListener(new MyJobListener(), GroupMatcher.jobGroupEquals("myJobGroup"));
        /**
         * 爲指定triggerGroup添加TriggerListener
         */
        scheduler.getListenerManager().addTriggerListener(new MyTriggerListener(), GroupMatcher.triggerGroupEquals
                ("myTriggerGroup"));

        scheduler.scheduleJob(jobDetail, trigger);
    }

    @Test
    public void testThree() throws SchedulerException, InterruptedException {
        JobDetail jobDetail = getJobDetail();

        //非持久化Job無關聯Trigger添加到Scheduler須要使用addJob第三個參數storeNonDurableWhileAwaitingScheduling爲true
        scheduler.addJob(jobDetail, false, true);

        //JobDetail 1<->* Trigger
        Trigger trigger1 = TriggerBuilder.newTrigger().forJob(jobDetail)
                .startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever()).build();

        Trigger trigger2 = TriggerBuilder.newTrigger().forJob(jobDetail)
                .startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();

        scheduler.scheduleJob(trigger1);
        scheduler.scheduleJob(trigger2);

        Thread.sleep(10000);
    }

    /**
     * 具體業務實現類,實現Job接口的execute方法便可
     */
    public static class MyJob implements Job {

        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            System.out.println("MyJob " + this.getClass().getCanonicalName());
        }
    }


    /**
     * JobListener實現
     * <p/>
     * JobListener方法執行順序
     * <p/>
     * 若是TriigerListener的vetoJobExecution返回true
     * triggerFired -> vetoJobExecution ->jobExecutionVetoed
     * <p/>
     * 若是TiggerListener的vetoJobExecution返回false
     * triggerFired -> vetoJobExecution ->jobToBeExecuted -> [Job execute] -> jobWasExecuted
     * ->[triggerMisfired|triggerComplete]
     */
    public static class MyJobListener implements JobListener {
        @Override
        public String getName() {
            return "MyJobListener";
        }

        @Override
        public void jobToBeExecuted(JobExecutionContext context) {
            System.out.println("jobToBeExecuted:" + context.getJobDetail().getDescription());
        }

        @Override
        public void jobExecutionVetoed(JobExecutionContext context) {
            System.out.println("jobExecutionVetoed:" + context.getJobDetail().getDescription());
        }

        @Override
        public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
            System.out.println("jobWasExecuted:" + context.getJobDetail().getDescription());
        }
    }

    /**
     * TriggerListener實現
     */
    public static class MyTriggerListener implements TriggerListener {

        @Override
        public String getName() {
            return "MyTriggerListener";
        }

        @Override
        public void triggerFired(Trigger trigger, JobExecutionContext context) {
            System.out.println("triggerFired:" + trigger.getDescription());
        }

        @Override
        public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
            System.out.println("vetoJobExecution:" + trigger.getDescription());
            return false;

            /**
             return:false
             triggerFired:MyTrigger
             vetoJobExecution:MyTrigger
             jobToBeExecuted:MyJobDetail
             MyJob secondriver.quartz.TestJobListener.MyJob
             jobWasExecuted:MyJobDetail
             triggerComplete:MyTrigger
             */
            /**
             return:true
             triggerFired:MyTrigger
             vetoJobExecution:MyTrigger
             jobExecutionVetoed:MyJobDetail
             */
        }

        @Override
        public void triggerMisfired(Trigger trigger) {
            System.out.println("triggerMisfired:" + trigger.getDescription());
        }

        @Override
        public void triggerComplete(Trigger trigger, JobExecutionContext context, Trigger.CompletedExecutionInstruction triggerInstructionCode) {
            System.out.println("triggerComplete:" + trigger.getDescription());
        }
    }
}


  上述代碼依賴Quartz框架的Maven配置:

  

<dependency>
   <groupId>org.quartz-scheduler</groupId>
   <version>2.2.1</version>
   <artifactId>quartz</artifactId>
</dependency>


  Quartz在Java應用做業調度方面提供了很是完備的實現,本文經過三個做業調度方面的關鍵詞和Quartz的用戶擴展Listener簡要介紹了Quartz的使用,更多內容能夠查看Quartz用戶手冊或者源代碼。

相關文章
相關標籤/搜索