三、Quartz中Scheduler的理解和使用

(一)、調度器是什么?有什么作用?

??調度器(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創建的所有資源(線程、數據庫連接等)。

一般情況下,調度器啟動后不需要做其他任何事情。

到此,調度器講述完畢,如果大家有什么問題,請在下方留言,謝謝!
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容