定時任務調度框架Quartz

1.前言

最近須要寫一個天天定點自動執行的定時任務,對於之前本身寫小項目,可能會選擇java自帶的Timer類,可是對於公司中的項目,Timer類實現定時任務只能有一個後臺線程執行任務,而且只能讓程序按照某個頻度執行,並不能在指定時間點執行。同時因爲通常大型項目會有多個job分別須要在不一樣的時間點自動執行,單線程的Timer知足不了需求。而任務調度框架Quartz恰好知足這些需求,我是實習公司的項目中就已經配置好了這個框架,在使用的時候瞭解了這個quartz,現總結以下。html

2.quartz是什麼?

Quartz是OpenSymphony開源組織在Job scheduling領域又一個開源項目,徹底由Java開發,能夠用來執行定時任務,相似於java.util.Timer。可是相較於Timer, Quartz增長了不少功能:

持久性做業 - 就是保持調度定時的狀態;
做業管理 - 對調度做業進行有效的管理; 
複製代碼

quartz主要包括三個部分的模塊,定時任務Job、觸發器Trigger、調度器Scheduler。
簡單的流程就是:調度器根據觸發器來執行任務。java

2.1 Job

  • Job:即被調度的任務,實現業務邏輯的接口,接口中只有一個方法execute。若是須要建立一個任務,必須得實現這個接口,任務每次被調用的時候都會執行這個execute方法的邏輯。
//預約義Job接口--pom.xml須要加載依賴的包
public interface Job {
    void execute(JobExecutionContext var1) throws JobExecutionException;
}

//任務邏輯經過實現Job接口,而且重寫execute方法,將須要執行的邏輯實現寫在execute函數中
public class TestJob implements Job {
      /**把要執行的操做,寫在execute方法中 */
      @Override
      public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
          SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
          System.out.println("I can do something...");
          System.out.println(sdf.format(new Date()));
      }
  }
 
參考:https://juejin.im/post/5a0c08c5f265da4335624c8f

//1. 建立一個JodDetail實例 將該實例與Hello job class綁定 (鏈式寫法)
JobDetail jobDetail = JobBuilder.newJob(QuartzOrderReturn.class)// 定義Job類爲QuartzOrderReturn類,這是真正的執行邏輯所在
                    .withIdentity(StrUtils.uuid())
                    .setJobData(jobDataMap)
                    .build();
複製代碼

2.2 Trigger

  • trigger:觸發器,用於定義任務調度的時間 規則。quartz有兩種常見的trigger:SimpleTrigger和CornTrigger。
  • SimpleTrigger 主要針對一些簡單的時間觸發進行配置使用,好比指定的時間開始而後在必定的時間間隔以內重複執行一個job,同時能夠任意指定重複的次數,可是不適合天天定時執行任務的場景,好比SimpleTrigger解決不了須要天天半夜十二點執行的任務。
//建立SimpleTrigger startTime end 分別表示觸發器的首次觸發時間和再也不被觸發的時間
 SimpleTrigger trigger = newTrigger()
                    .withIdentity("trigger", "group")
                    .startAt(startTime)
                    .endAt(end)
                    .withSchedule(
                            simpleSchedule().withIntervalInHours(
                                    executeFrequency).withRepeatCount(
                                    executeBatch)).build();
複製代碼
  • CronTrigger 能夠配置更復雜的觸發時刻表,基於日曆的做業觸發器。使用SimpleTrigger觸發器須要設置不一樣的屬性支撐,代碼編寫比較多,而且不靈活。而CornTrigger就比較靈活,能夠經過設計Corn表達式來控制複雜的觸發時間表。算法

  • Corn表達式:用於配置CornTrigger實例,由7個表達式組成的字符串,描述了時間表的詳細信息。bash

//建立CornTrigger 好比下面的就是設計天天中午十二點整觸發
CronTrigger trigger = newTrigger().withIdentity(triggerKey).withSchedule(cronSchedule("0 0 12 * * ?")).build();
// 把job和trigger加入調度
scheduler.scheduleJob(jobDetail, trigger);
//啓動scheduler
scheduler.start();

複製代碼

對於Corn的理解參考: mp.weixin.qq.com/s/-0kwxC2lz…?
在線生成Corn表達式: cron.qqe2.com/

2.3 Scheduler

  • Scheduler:在每次調度器執行job時,它在調用execute方法前會建立一個新的job實例,當調用完成以後,關聯的job對象實例會被釋放,釋放的實例會被垃圾回收機制回收。
  • Scheduler能夠將Trigger綁定到某一JobDetail中,這樣當Trigger觸發時,對應的Job就被執行。一個Job能夠對應多個Trigger,但一個Trigger只能對應一個Job。
// 把job和trigger加入調度
scheduler.scheduleJob(jobDetail, trigger);
//啓動scheduler
scheduler.start();
複製代碼

//一個完整的實例
private void quartzOrderReturn(List<String> returnIds) {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("returnIds", returnIds);
            //1. 建立一個JodDetail實例 將該實例與Hello job class綁定 (鏈式寫法)
            JobDetail jobDetail = JobBuilder.newJob(QuartzOrderReturn.class)// 定義Job類爲QuartzOrderReturn類,這是真正的執行邏輯所在
                    .withIdentity(StrUtils.uuid())
                    .setJobData(jobDataMap)
                    .build();
            // 2. 定義一個Trigger,定義該job在10秒後執行,而且執行一次
            Date startTime = new Date();
            startTime.setTime(startTime.getTime() + 10000L);
            SimpleTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(StrUtils.uuid(), HeaderNameConstants.getQuartzTrigger()).startNow()// 定義名字和組
                    .startAt(startTime)
                    .withSchedule(SimpleScheduleBuilder
                            .simpleSchedule()
                            .withIntervalInSeconds(2)//定義時間間隔是2秒
                            .withRepeatCount(0)//定義重複執行次數是無限次
                    )
                    .build();
            // 4. 將trigger和jobdetail加入這個調度
            scheduler.scheduleJob(jobDetail, trigger);
            // 5. 啓動scheduler
            scheduler.start();
            // 6. 任務執行後20秒後休眠
            Thread.sleep(startTime.getTime() + 20000L);
            // 7. 若是定時任務開啓則關閉
            if (scheduler.isStarted()) {
                scheduler.shutdown(true);
            }
        } catch (SchedulerException | InterruptedException e) {
            e.printStackTrace();
        }
    }
複製代碼

2.4 結構圖

  • IJob:預實現的Job接口
  • MyJob:實現Job接口,定時任務邏輯寫再execute函數
  • JobDetail,顧名思義,就是表示關於每一個Job的相關信息,它主要包括兩個核心組件,即Job Task和JobData Map
  • Trigger,表示觸發器,根據配置規則來觸發執行計劃調度job,它主要包括兩個核心組件,即SimpleTrigger和CronTrigger
  • IJobStore,表述任務存儲器,主要存儲job和trigger相關信息。
  • ISchedulerFactory,表示任務計劃工廠,用來管理任務計劃IScheduler。
  • IScheduler,表述任務計劃,它至關於一個容器,具體job和job相關trigger就可以被注入其中,從而實現任務計劃調度。其主要經常使用的方法:Start --啓動執行計劃 Shutdowm --關閉執行計劃
//每一個2秒執行一次
            string cronParam = "*/2 * * * * ?";
            //建立計劃任務抽象工廠
            ISchedulerFactory sf = new StdSchedulerFactory();
            //建立計劃任務
            IScheduler sched = sf.GetScheduler();
            //建立job
            JobDetail job = new JobDetail("myJob","group", typeof(MyJob));
            //建立觸發器
            Trigger trigger = new CronTrigger("myTrigger","group",cronParam);
            //將job和trigger注入到計劃任務中
            sched.ScheduleJob(job, trigger);
            //啓動計劃任務
            sched.Start();
            //關閉計劃任務
            //sched.Shutdown();
複製代碼

參考: www.cnblogs.com/wangjiming/…

3.定時任務如何實現並調度:TimeWheel

定時通常是使用時間輪(time wheel)算法實現。 時間輪算法簡單來講能夠用下圖表示,其主體是一個循環列表,框架

新任務加入時,會根據目前指針所在位置和須要等待的時間,肯定保存在時鐘的哪一個位置。時間輪有3個重要的屬性參數,ticksPerWheel(一輪的tick數),tickDuration(一個tick的持續時間)以及 timeUnit(時間單位)。
例如 當ticksPerWheel=60,tickDuration=1,timeUnit=秒,這就和現實中秒針走動徹底相似了,咱們就用這種狀況舉例子。箭頭運行到一個位置時,就運行相應的任務,而後經過sleep將時間補足一秒,正好就開始下一個tick了。這樣循環往復,就可讓每一個任務在須要的時間執行。

參考連接:www.zhihu.com/question/41… www.kafka.cc/archives/24…ide

4.項目中的擴展

1.抽象封裝Job類函數

2.頁面管理多個定時任務post

5.總結

  • 理解quartz是什麼,包括哪些部分?
  • 理解quartz是如何實現定時任務的?
  • 理解quartz是如何管理調度多個定時任務的?
相關文章
相關標籤/搜索