深刻解讀Quartz任務調度器

深刻解讀Quartz任務調度器

1.Quartz簡介

1.1.概要

  Quartz是OpenSymphony提供的強大的開源任務調度框架。  
  官網:www.quartz-scheduler.org
  純Java實現,精細控制排程。
java

1.2.Quartz特色

  1. 強大的調度能力
  2. 靈活的應用方式
  3. 強大的分佈式和集羣能力

    1.3.Quartz設計模式

  • Builder模式
  • 組件模式
  • Factory模式
  • 鏈式寫法

    1.4.Quartz體系結構

    1.4.1.三大核心

  • 調度器
  • 任務
  • 觸發器

1.4.2.重要組成

1)任務: 數據庫

  • Job:表示一個工做,要執行的具體內容。此接口中只有一個方法。要建立一個任務,必須得實現這個接口。該接口只有一個execute方法,任務每次被調用的時候都會執行這個execute方法的邏輯,相似TimerTask的run方法,在裏面編寫業務邏輯。 設計模式

    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()));
          }
      }複製代碼

生命週期:在每次調度器執行job時,它在調用execute方法前會建立一個新的job實例,當調用完成以後,關聯的job對象實例會被釋放,釋放的實例會被垃圾回收機制回收。bash

  • JobBuilder:可向任務傳遞數據,一般狀況下,咱們使用它就可向任務類發送數據了,若有特別複雜的傳遞參數,它提供了一個傳遞遞:JobDataMap對象的方法  服務器

    JobDetail jobDetail =  JobBuilder.newJob(TestJob.class).withIdentity("testJob","group1").build();複製代碼
  • JobDetail:用來保存咱們任務的詳細信息。一個JobDetail能夠有多個Trigger,可是一個Trigger只能對應一個JobDetail。下面是JobDetail的一些經常使用的屬性和含義:  併發

  

  • JobStore:負責跟蹤全部你給scheduler的「工做數據」:jobs, triggers, calendars, 等。框架

    • RAMJobStore:是使用最簡單的也是最高效(依據CPU時間)的JobStore 。RAMJobStore 正如它名字描述的同樣,它保存數據在RAM。缺點是你的應用結束以後全部的數據也丟失了--這意味着RAMJobStore 不具備保持job和trigger持久的能力。對於一些程序是能夠接受的,甚至是指望的,但對於其餘的程序多是災難性的。使用RAMJobStore配置Quartz:配置以下分佈式

      org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore 複製代碼
    • JDBCJobStore:以JDBC的方式保存數據在數據庫中。它比RAMJobStore的配置複雜一點,也沒有RAMJobStore快。然而,性能缺點不是糟透了,特別是若是你在數據庫表主鍵上創建了索引。在機器之間的LAN(在scheduler 和數據庫之間)合理的狀況下,檢索和更新一個被觸發的Trigger花費的時間少於10毫秒。幾乎適用於全部的數據庫,普遍用於 Oracle。PostgreSQL, MySQL, MS SQLServer, HSQLDB, 和DB2。使用JDBCJobStore以前你必須首先建立一系列Quartz要使用的表。你能夠發現表建立語句在Quartz發佈目錄的 「docs/dbTables」下面。你須要肯定你的應用要使用的事務類型。若是你不想綁定調度命令(例如增長和移除Trigger)到其餘的事務,你可使用JobStoreTX (最經常使用的選擇)做爲你的Jobstore。若是你須要Quartz和其餘的事務(例如在J2EE應用服務器中)一塊兒工做,你應該使用JobStoreCMT ,Quartz 將讓應用服務器容器管理這個事務。使用JobStoreTx配置Quartz:ide

      org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX  
        org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate  
        #配置表的前綴 
        org.quartz.jobStore.tablePrefix = QRTZ_  
        #使用JNDI數據源的時候,數據源的名字 
        org.quartz.jobStore.dataSource = myDS      複製代碼
    • TerracottaJobStore:提供了一個方法:在不使用數據庫的狀況下使它具備收縮性和強壯性。能夠是集羣的也能夠是非集羣的,在這兩種狀況下爲你的job數據提供了一個存儲機制用於應用程序重啓之間持久,由於數據是存儲在Terracotta服務器。它的性能比使用數據庫訪問JDBCJobStore好一點兒(大約是一個數量級),可是明顯比RAMJobStore慢。使用TerracottaJobStore配置Quartz:函數

      org.quartz.jobStore.class = org.terracotta.quartz.TerracottaJobStore  
        org.quartz.jobStore.tcConfigUrl = localhost:9510  複製代碼
  • JobDataMap:中能夠包含不限量的(序列化的)數據對象,在job實例執行的時候,可使用其中的數據;JobDataMap是Java Map接口的一個實現,額外增長了一些便於存取基本類型的數據的方法。

    • 存:

      JobDetail jobDetail =  JobBuilder.newJob(TestJob.class).withIdentity("testJob","group1").usingJobData("date1","存內容").build(); 複製代碼
    • 取:

      public class TestJob implements Job {
            /**把要執行的操做,寫在execute方法中  */
            @Override
            public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
                JobKey key = jobExecutionContext.getJobDetail().getKey();
                JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
                String date1 = jobDataMap.getString("date1");
            }
        }複製代碼

2)觸發器:用來觸發執行Job

2.1)觸發器通用屬性:

  • Jobkey:表示job實例的標識,觸發器被觸發時,該指定的job實例會被執行
  • StartTime:表示觸發器的時間表首次被觸發的時間,它的值類型爲:java.util.Date
  • EndTime:指定觸發器的再也不被觸發的時間,它的值類型爲:java.util.Date

2.2)觸發器類型:

  • SimpleTrigger: 主要是針對一些相對簡單的時間觸發進行配置使用,好比在指定的時間開始而後在必定的時間間隔以內重複執行一個Job,同時能夠任意指定重複的次數。下面就是使用一個SimpleTrigger的例子:

    //建立觸發器 每3秒鐘執行一次(無開始時間和結束時間)
      Trigger trigger = TriggerBuilder.newTrigger()
                  .withIdentity("trigger1", "group3")
                  .withSchedule(
                  SimpleScheduleBuilder.simpleSchedule()
                  .withIntervalInSeconds(3).repeatForever()).build();
      //建立觸發器 每3秒鐘執行一次(有開始時間和結束時間)
       long now = new Date().getTime();
      Date start = new Date(now+6000);
      Date end = new Date(now+12000);
      //建立觸發器 每3秒鐘執行一次
      Trigger trigger = TriggerBuilder.newTrigger()
                        .withIdentity("trigger1", "group3")
                        .startAt(start)
                        .endAt(end)
                        .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever()).build();複製代碼

    SimpleTrigger具備豐富的構造函數,根據業務需求構造不一樣的構造函數。

  • CronTrigger: 能夠配置更復雜的觸發時刻表,基於日曆的做業觸發器,而不像SimpleTrigger那樣精確指定間隔時間,比SimpleTrigger更加經常使用。

  Cron表達式:用於配置CronTrigger實例,是由7個表達式組成的字符串,描述了時間表的詳細信息。
  格式爲:[秒][分][時][日][月][周][年]
  Cron表達式特殊字符意義對應表:
  


  通配符說明:
  

  Cron表達式例子:
  

TriggerBuilder.newTrigger().withIdentity("trigger2","group2")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 0 9 ? * 6L *")).build();複製代碼

  Cron表達式小技巧:
  1. ‘L’和‘W’能夠一塊兒組合使用
  2. 周字段英文字母不區分大小寫即MOM與mom相同
  3. 利用工具,在線生成cron表達式:cron.qqe2.com/

  • NthIncludedDayTrigger:是 Quartz 開發團隊最新加入到框架中的一個 Trigger。它設計用於在每一間隔類型的第幾天執行 Job。例如,你要在每月的 15 號執行開票的 Job,用 NthIncludedDayTrigger就再合適不過了。

    NthIncludedDayTrigger trigger = new NthIncludedDayTrigger("NthIncludedDayTrigger",Scheduler.DEFAULT_GROUP);
                  trigger.setN(15);
                  trigger.setIntervalType(NthIncludedDayTrigger.INTERVAL_TYPE_MONTHLY);複製代碼

3)調度器Scheduler
  表明一個Quartz的獨立運行容器,Trigger和JobDetail能夠註冊到Scheduler中,二者在Scheduler中擁有各自的組及名稱,組及名稱是Scheduler查找定位容器中某一對象的依據,Trigger的組及名稱必須惟一,JobDetail的組和名稱也必須惟一(但能夠和Trigger的組和名稱相同,由於它們是不一樣類型的)。Scheduler定義了多個接口方法,容許外部經過組及名稱訪問和控制容器中Trigger和JobDetail。
  Scheduler能夠將Trigger綁定到某一JobDetail中,這樣當Trigger觸發時,對應的Job就被執行。一個Job能夠對應多個Trigger,但一個Trigger只能對應一個Job。
  能夠經過SchedulerFactory建立一個Scheduler實例。Scheduler擁有一個SchedulerContext,它相似於ServletContext,保存着Scheduler上下文信息,Job和Trigger均可以訪問SchedulerContext內的信息。SchedulerContext內部經過一個Map,以鍵值對的方式維護這些上下文數據,SchedulerContext爲保存和獲取數據提供了多個put()和getXxx()的方法。能夠經過Scheduler# getContext()獲取對應的SchedulerContext實例;

SchedulerFactory schedulerfactory=new StdSchedulerFactory();
    Scheduler scheduler = schedulerfactory.getScheduler();

     DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();
    try {
        Scheduler scheduler = factory.getScheduler();
    } catch (SchedulerException e) {
        e.printStackTrace();
    }複製代碼

4)SchedulerFactory:

  • 使用一組參數(java.util.Properties)來建立和出書啊Quartz調度器
  • 配置參數通常存儲在quartz.properties中
  • 調用getScheduler方法就能建立和初始化調度器

5)quartz.properties:
Quartz-Job的quartz.properties配置文件說明,此文件在quartz的jar包有,可直接拿過來使用不過只有基本的幾個配置 本身可根據須要進行擴充;另外若是項目中沒有對該配置文件重寫,則Quartz會加載本身jar包中的quartz.properties文件。

# Default Properties file for use by StdSchedulerFactory 
    # to create a Quartz Scheduler Instance, if a different 
    # properties file is not explicitly specified. 
    # 
    # =========================================================================== 
    # Configure Main Scheduler Properties 調度器屬性 
    # =========================================================================== 
    org.quartz.scheduler.instanceName: DefaultQuartzScheduler  
    #org.quartz.scheduler.instanceid:AUTO 
    org.quartz.scheduler.rmi.export: false  
    org.quartz.scheduler.rmi.proxy: false  
    org.quartz.scheduler.wrapJobExecutionInUserTransaction: false  
    # =========================================================================== 
    # Configure ThreadPool 線程池屬性 
    # =========================================================================== 
    #線程池的實現類(通常使用SimpleThreadPool便可知足幾乎全部用戶的需求) 
    org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool  
    #指定線程數,至少爲1(無默認值)(通常設置爲1-100直接的整數合適) 
    org.quartz.threadPool.threadCount: 10  
    #設置線程的優先級(最大爲java.lang.Thread.MAX_PRIORITY 10,最小爲Thread.MIN_PRIORITY 1,默認爲5) 
    org.quartz.threadPool.threadPriority: 5  
    #設置SimpleThreadPool的一些屬性 
    #設置是否爲守護線程 
    #org.quartz.threadpool.makethreadsdaemons = false 
    #org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true 
    #org.quartz.threadpool.threadsinheritgroupofinitializingthread=false 
    #線程前綴默認值是:[Scheduler Name]_Worker 
    #org.quartz.threadpool.threadnameprefix=swhJobThead; 
    # 配置全局監聽(TriggerListener,JobListener) 則應用程序能夠接收和執行 預約的事件通知 
    # =========================================================================== 
    # Configuring a Global TriggerListener 配置全局的Trigger監聽器 
    # MyTriggerListenerClass 類必須有一個無參數的構造函數,和 屬性的set方法,目前2.2.x只支持原始數據類型的值(包括字符串) 
    # =========================================================================== 
    #org.quartz.triggerListener.NAME.class = com.swh.MyTriggerListenerClass 
    #org.quartz.triggerListener.NAME.propName = propValue 
    #org.quartz.triggerListener.NAME.prop2Name = prop2Value 
    # =========================================================================== 
    # Configuring a Global JobListener 配置全局的Job監聽器 
    # MyJobListenerClass 類必須有一個無參數的構造函數,和 屬性的set方法,目前2.2.x只支持原始數據類型的值(包括字符串) 
    # =========================================================================== 
    #org.quartz.jobListener.NAME.class = com.swh.MyJobListenerClass 
    #org.quartz.jobListener.NAME.propName = propValue 
    #org.quartz.jobListener.NAME.prop2Name = prop2Value 
    # =========================================================================== 
    # Configure JobStore 存儲調度信息(工做,觸發器和日曆等) 
    # =========================================================================== 
    # 信息保存時間 默認值60秒 
    org.quartz.jobStore.misfireThreshold: 60000  
    #保存job和Trigger的狀態信息到內存中的類 
    org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore  
    # =========================================================================== 
    # Configure SchedulerPlugins 插件屬性 配置 
    # =========================================================================== 
    # 自定義插件 
    #org.quartz.plugin.NAME.class = com.swh.MyPluginClass 
    #org.quartz.plugin.NAME.propName = propValue 
    #org.quartz.plugin.NAME.prop2Name = prop2Value 
    #配置trigger執行歷史日誌(能夠看到類的文檔和參數列表) 
    org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin    
    org.quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}    
    org.quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}    
    #配置job調度插件 quartz_jobs(jobs and triggers內容)的XML文檔 
    #加載 Job 和 Trigger 信息的類 (1.8以前用:org.quartz.plugins.xml.JobInitializationPlugin) 
    org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin  
    #指定存放調度器(Job 和 Trigger)信息的xml文件,默認是classpath下quartz_jobs.xml 
    org.quartz.plugin.jobInitializer.fileNames = my_quartz_job2.xml    
    #org.quartz.plugin.jobInitializer.overWriteExistingJobs = false 
    org.quartz.plugin.jobInitializer.failOnFileNotFound = true    
    #自動掃描任務單並發現改動的時間間隔,單位爲秒 
    org.quartz.plugin.jobInitializer.scanInterval = 10  
    #覆蓋任務調度器中同名的jobDetail,避免只修改了CronExpression所形成的不能從新生效狀況 
    org.quartz.plugin.jobInitializer.wrapInUserTransaction = false  
    # =========================================================================== 
    # Sample configuration of ShutdownHookPlugin ShutdownHookPlugin插件的配置樣例 
    # =========================================================================== 
    #org.quartz.plugin.shutdownhook.class = \org.quartz.plugins.management.ShutdownHookPlugin 
    #org.quartz.plugin.shutdownhook.cleanShutdown = true 
    # 
    # Configure RMI Settings 遠程服務調用配置 
    # 
    #若是你想quartz-scheduler出口自己經過RMI做爲服務器,而後設置「出口」標誌true(默認值爲false)。 
    #org.quartz.scheduler.rmi.export = false 
    #主機上rmi註冊表(默認值localhost) 
    #org.quartz.scheduler.rmi.registryhost = localhost 
    #註冊監聽端口號(默認值1099) 
    #org.quartz.scheduler.rmi.registryport = 1099 
    #建立rmi註冊,false/never:若是你已經有一個在運行或不想進行建立註冊 
    # true/as_needed:第一次嘗試使用現有的註冊,而後再回來進行建立 
    # always:先進行建立一個註冊,而後再使用回來使用註冊 
    #org.quartz.scheduler.rmi.createregistry = never 
    #Quartz Scheduler服務端端口,默認是隨機分配RMI註冊表 
    #org.quartz.scheduler.rmi.serverport = 1098 
    #true:連接遠程服務調度(客戶端),這個也要指定registryhost和registryport,默認爲false 
    # 若是export和proxy同時指定爲true,則export的設置將被忽略 
    #org.quartz.scheduler.rmi.proxy = false 複製代碼
相關文章
相關標籤/搜索