三、Quartz中Scheduler的理解和使用

weixin_34146805發表於2018-02-02
(一)、排程器是什麼?有什麼作用?

  排程器(Scheduler)是Quartz框架的心臟,用來管理觸發器和Job,並保證Job能被觸發執行。程式設計師與框架內部之間的呼叫都是通過org.quartz.Scheduler介面來完成的。對於Scheduler介面的實現,其實只是核心排程(org.quartz.core.QuartzScheduler)的一個代理,對代理的方法進行呼叫時會傳遞到底層核心排程例項上。QuartzScheduler處於Quartz框架的根位置,驅動著整個Quartz框架。

(二)、建立排程器

  Scheduler介面有兩個實現類,分別為StdScheduler(標準預設排程器)和RemoteScheduler(遠端排程器),接下來重點講述StdScheduler例項。
  那麼如何建立排程器例項呢?大家可能立馬會想到通過new的方式顯式的建立StdScheduler例項。StdScheduler只提供了一個帶參構造方法,此構造需要傳遞QuartzScheduler和SchedulingContext兩個例項引數:

public StdScheduler(QuartzScheduler sched, SchedulingContext schedCtxt)

  然而我們一般不使用構造方法去建立排程器,而是通過排程器工廠來建立。排程器工廠介面org.quartz.SchedulerFactory提供了兩種不同型別的工廠實現,分別是org.quartz.impl.DirectSchedulerFactoryh和org.quartz.impl.StdSchedulerFactory,下面我們分別講述:

(1)、使用DirectSchedulerFactory工廠建立

  此工廠方式建立適用於想絕對控制Scheduler例項的場景,下面用最簡單的方式通過DirectSchedulerFactory建立一個例項:

  public static void main(String[] args) {
      try {
        DirectSchedulerFactory schedulerFactory = DirectSchedulerFactory.getInstance();
        // 表示以3個工作執行緒初始化工廠
        schedulerFactory.createVolatileScheduler(3);
        Scheduler scheduler = schedulerFactory.getScheduler();  
      } catch (SchedulerException e) {
        e.printStackTrace();
      }
  }

建立步驟:
  1、通過DirectSchedulerFactory的getInstance方法得到拿到例項
  2、呼叫createXXX方法初始化工廠
  3、呼叫工廠例項的getScheduler方法拿到排程器例項

  可以看出,DirectSchedulerFactory是通過createXXX方法傳遞配置引數來初始化工廠,這種初始化方式是一種硬編碼,在工作中用到的情況會很少。

(2)、使用StdSchedulerFactory工廠建立

此工廠是依賴一系列的屬性來決定如何建立排程器例項的。
屬性提供的方式有三種:
  1、通過java.util.Properties屬性例項
  2、通過外部屬性檔案提供
  3、通過有屬性檔案內容的 java.io.InputStream 檔案流提供

    public static void main(String[] args) {
        try {
            StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
            
            // 第一種方式 通過Properties屬性例項建立
            Properties props = new Properties();
            props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, "org.quartz.simpl.SimpleThreadPool");
            props.put("org.quartz.threadPool.threadCount", 5);
            schedulerFactory.initialize(props);
            
            // 第二種方式 通過傳入檔名
            // schedulerFactory.initialize("my.properties");
            
            // 第三種方式 通過傳入包含屬性內容的檔案輸入流
            // InputStream is = new FileInputStream(new File("my.properties"));
            // schedulerFactory.initialize(is);

            // 獲取排程器例項
            Scheduler scheduler = schedulerFactory.getScheduler();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • 第一種方式向工廠傳入了兩個屬性,分別是執行緒池的類名和執行緒池大小,這兩個屬性是必須的,因為工廠沒有給它們指定預設值。
  • 第二種方式是通過定義一個外部屬性檔案,底層實現是:首先通過Thread.currentThread().getContextClassLoader().getResourceAsStream(filename)獲取檔案流,然後使用Properties例項的load方法載入檔案流形成屬性例項,最後在通過initialize(props)初始化完成。
  • 第三種方式就是直接使用Properties例項的load方法載入檔案流形成屬性例項,再在通過initialize(props)初始化完成。

  StdSchedulerFactory工廠還提供了無引數的initialize()方法,此方法本質也是通過載入屬性檔案,initialize()方法總是能載入成功的,因為quartz的jar包中有預設的quartz.properties檔案,具體的載入步驟:
  1、檢查系統屬性中是否設定了檔名,通過System.getProperty("org.quartz.properties")
  2、如果沒有設定,使用預設的quartz.properties作為要載入的檔名
  3、然後先從當前工作目錄中載入這個檔案,如果沒有找到,再從系統 classpath 下載入這個檔案

  StdSchedulerFactory工廠還可以不主動呼叫initialize()方法進行初始化,而是直接使用StdSchedulerFactory的靜態方法getDefaultScheduler()拿到排程器。

(三)、管理排程器

  通過上述方法拿到排程器例項以後,在排程的生命週期中可以做以下工作,例如:啟動排程器,設定排程器為standby模式,繼續或停止排程器。
(1)啟動Scheduler
  當排程器初始化完成,並且Job和Trigger也註冊完成,此時就可以呼叫scheduler.start()啟動排程器了。start()方法一旦被呼叫,排程器就開始搜尋需要執行的Job。
(2)設定standby模式
  設定Scheduler為standby模式會讓排程器暫停尋找Job去執行。
  應用場景舉例:當需要重啟資料庫時可以先將排程器設定為standby模式,待資料庫啟動完成後再通過start()啟動排程器。
(3)停止排程器
  呼叫shutdown()或shutdown(boolean waitForJobsToComplete)方法停止排程器。第二個方法表示等待所有正在執行的job執行完畢後才停止排程器。shutdown方法呼叫後,就不可以再呼叫start方法了,因為shutdown方法會銷燬Scheduler建立的所有資源(執行緒、資料庫連線等)。

一般情況下,排程器啟動後不需要做其他任何事情。

到此,排程器講述完畢,如果大家有什麼問題,請在下方留言,謝謝!

相關文章