2012年2月1日

Quartz in Spring:使用多個Scheduler的參數設定


 
多數人在使用 Quartz 時一開始都只使用一個 Scheduler,
而且通常也只執行一個排程,
然而隨著經驗累積、project變大、需求變多,
慢慢地也會出現要執行多個排程工作的需求。
這篇就是要解釋如何在 Spring 的 xml 設定檔中達成這個目的。


在開始多個排程設定前我們先來複習一下單一排程工作的設定:
下面 xml 中整體的概念其實是由 schedulerFactoryBean 抓到預設的 scheduler,
讓預設的 scheduler ,執行排程 cronTrigger,而排程執行的目標是 jobDetail
也就是 targetClass 中 executeMethod 要做的事

以下由 xml 依序解釋每個段落的設定有何意義:
第一行是要讓 Spring 抓到 targetClass 的 Bean,
下面一段則是定義要執行的工作 jobDetail
這個工作的目標為 targetClass 中的 executeMethod

接著設定一個排程 cronTrigger 來執行 jobDetail
藉由設定 cronExpression 可以調整要執行的時間,
而最下面則是利用 schedulerFactoryBean 抓到名字是空字串的預設 Scheduler,
預設 Scheduler 就是實際去執行排程的執行者,可以執行不只一個排程
<bean id="targetClass" class="my.project.class"/>

<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="targetClass"/>
    <property name="targetMethod" value="executeMethod"/>
</bean>

<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail" ref="jobDetail"/>
    <!-- 每星期天 0:00 分執行-->
    <property name="cronExpression" value="0 0 0 ? * SUN"/>
</bean>

<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="cronTrigger"/>
        </list>
    </property>
</bean>

看完上面的設定我們可以發現一個結論,
其實一個 Scheduler 就能執行多個排程了。
只要在 triggers 的 list 中插入更多的 trigger 即可!
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="cronTrigger"/>
            <ref bean="cronTrigger2"/>
            <ref bean="cronTrigger3"/>
        </list>
    </property>
</bean>

但有時我們還是會需要多個 Scheduler,
因為大家都使用預設的 scheduler 時,
若有某模組停用了這個 scheduler,則所有的排程都會停下來。
所以為了安全起見,最好還是用不同的 scheduler。

那麼依照上面 xml 檔的設定要怎麼加多個 scheduler 呢?
按照設定檔來看,大家一開始的直覺可能就是多放幾個schedulerFactoryBean
然而這種想法是沒有用的!
原因是因為SchedulerFactoryBean是透過StdSchedulerFactory回傳 scheduler ,
而且每個 Scheduler都是是註冊在SchedulerRepository中。
而 SchedulerRepository中是用一個 MAP 存放所有的  scheduler ,
並依據 scheduler 的 name 當成 key 來找到 scheduler。

所以就算我們有多個 schedulerFactoryBean
仍然會透過相同的 SchedulerRepository 來尋找 scheduler,
但我們用的都是以空字串為名的 scheduler,
所以最終回傳的都會是同一個 scheduler,
即使我們用多個 schedulerFactoryBean 也一樣。

為了解決這個問題,我們要在每個 schedulerFactoryBean 的設定中,
加入 schedulerName 這個參數,
這樣就可以為這個 schedulerFactoryBean 找到的 scheduler 加上名字,
而不是只用預設的空字串。
名字不一樣後,每個 schedulerFactoryBean 當然就可以抓到各自的 scheduler 囉!
設定方式如下:
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="cronTrigger"/>
            <ref bean="cronTrigger2"/>
            <ref bean="cronTrigger3"/>
        </list>
    </property>
    <property name="schedulerName">
        <value>jobScheduler</value>
    </property>
</bean>


若想知道更多有關 Java 時間相關的轉換、排程、格式化輸出輸入等應用,
還有更多有關 Quartz 的應用方式,請見:
Java 時間日期處理範例大全:含時間單位格式轉換、期間計算、排程等


關鍵字:job, jobDetail, 多個, 排程, 工作, 實例, instance, spring, quartz
參考資料:


更多精選推薦文章