1. 程式人生 > >關於quartz的SimpleTrigger執行問題

關於quartz的SimpleTrigger執行問題

Quartz的主要介面類是Schedule、Job、Trigger,而觸發器Trigger就是定時任務的觸發時間,它規定安排了關聯的任務會在什麼時候執行,並且表明了再次執行的時機。

Quartz提供了多種觸發器:  

                                                   

 

我們詳細講解最常用的兩種觸發器:簡單觸發器SimpleTrigger、基於Cron表示式的觸發器CronTrigger

簡單觸發器SimpleTrigger


SimpleTrigger是介面Trigger的一個具體實現,它可以觸發一個已經安排進排程程式(任務執行計劃)的任務,並可以指定時間間隔重複執行該任務。

SimpleTrigger 包含幾個特點:開始時間、結束時間、重複次數以及重複執行的時間間隔

重複的次數可以是零,一個正整數,或常量SimpleTrigger.REPEAT_INDEFINITELY。 
重複執行的時間間隔可以是零,或者long型別的數值表示毫秒。值得注意的是,零重複間隔會造成觸發器同時發生(或接近同時作為排程管理)。 
“結束時間”的屬性會重寫重複的次數,這可能是有用的,如果你想建立一個觸發器,如每10秒觸發一次,直到一個給定的時刻,而不是要計算的次數,它會在開始時間和結束時間重複執行。結束時間一到,就算你指定了重複次數很多次(比如執行10W次),但是時間一到它將不再執行。

SimpleTrigger 例項建立依賴於TriggerBuilder 和SimpleScheduleBuilder ,使用Quartz提供的DSL風格建立觸發器例項, 
首先靜態引入builder,引入時間builder——DateBuilder:

import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.DateBuilder.*:

我們可以建立很多不同形式的觸發器:

建立一個指定時間開始執行,但是不重複的觸發器


使用startAt(java.util.Date)設定觸發器的第一次執行時間:

SimpleTrigger trigger = (SimpleTrigger) newTrigger()
    .withIdentity("trigger1", "group1")
    .startAt(myStartTime) // some Date
    .forJob("job1", "group1") // identify job with name, group strings
    .build();

 


建立一個指定時間開始執行,每10s執行一次,共執行10次的觸發器


使用SimpleScheduleBuilder的withIntervalInSeconds(N)方法可以指定間隔N秒就執行一次;withRepeatCount(M)可以指定執行次數M。

trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .startAt(myTimeToStartFiring)  // if a start time is not given (if this line were omitted), "now" is implied
    .withSchedule(simpleSchedule()
        .withIntervalInSeconds(10)
        .withRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
    .forJob(myJob) // identify job with handle to its JobDetail itself                   
    .build();


SimpleScheduleBuilder有很多類似的方法,API如下: 

                       è¿éåå¾çæè¿°

建立一個在未來第五分鐘的時候執行一次的觸發器


使用DateBuilder的futureDate方法可以指定在未來時間執行。

trigger = (SimpleTrigger) newTrigger()
    .withIdentity("trigger5", "group1")
    .startAt(futureDate(5, IntervalUnit.MINUTE)) 
    .forJob(myJobKey) /* job的jobKey*/
    .build();



建立一個馬上執行、每個5分鐘執行、知道22:00結束執行的觸發器


使用TriggerBuilder的startNow()方法立即觸發(scheduler呼叫start時算起,視優先順序而定); 
withIntervalInMinutes(5)每個5分鐘執行一次; 
repeatForever()一直重複; 
endAt(dateOf(22, 0, 0))知道22:00終結觸發器:

trigger = newTrigger()
    .withIdentity("trigger7", "group1")
    .startNow()
    .withSchedule(simpleSchedule()
        .withIntervalInMinutes(5)
        .repeatForever())
    .endAt(dateOf(22, 0, 0))
    .build();


建立一個在偶數小時執行、每兩個小時執行一次的觸發器


trigger = newTrigger()
    .withIdentity("trigger8") // group未指定,則會使用預設的組名
    .startAt(evenHourDate(null)) // 在下一個偶數小時開始執行(00:00:00、02:00:00、04:00:00等)
    .withSchedule(simpleSchedule()
        .withIntervalInHours(2)  //每隔兩小時執行一次
        .repeatForever())        //一直重複執行
    .build();


值得注意的是,如果沒有呼叫startAt(..)方法,預設使用startNow()。 
建議花點時間逐個嘗試使用TriggerBuilder、SimpleScheduleBuilder 和DateBuilder提供的API方法以加深理解。

 

關於簡單觸發器”熄火”的指令


SimpleTrigger 包含一些指令在它”熄火”時可以告知Quartz怎麼去處理。這些指令包含在SimpleTrigger 的常量中。

REPEAT_INDEFINITELY - 用於表示觸發器的“重複計數”是不確定的。或者換句話說,觸發應該不斷重複直到觸發的結尾時間戳
MISFIRE_INSTRUCTION_FIRE_NOW - 如果熄火,該指令會告訴Quartz應該馬上再次觸發
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT - 如果熄火,該指令會告訴Quartz馬上執行並計數累計到已經執行的次數當中去,如果結束時間已經過了,則不會再執行。
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT - 如果熄火,會告訴Quartz想要現在就執行一次(即使現在不是它原本計劃的觸發時間)
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT - 如果熄火,會告訴Quartz在下一次執行時間再次開始執行


一個使用”熄火”策略的觸發器示例:

 

trigger = newTrigger()
    .withIdentity("trigger7", "group1")
    .withSchedule(simpleSchedule()
        .withIntervalInMinutes(5)
        .repeatForever()
        .withMisfireHandlingInstructionNextWithExistingCount())
    .build();


基於Cron表示式的觸發器CronTrigger


CronTrigger通常使用得比SimpleTrigger等多一些。特別是基於日曆的概念,而不是對具體間隔的行為。

通過CronTrigger,你可以指定”每個星期五的中午”、”每個工作日上午9:30”,甚至是”一月的每星期一的上午9點至10點之間的每5分鐘,星期三和星期五”(這長串直接懵逼了…)執行。

 

Cron表示式


首先了解Cron表示式,它是用於配製CronTrigger例項的。Cron表示式,實際上是由七個子表示式組成的字串,它描述了不同的排程細節。這些子表示式是用空格分隔的,並表示: 
秒 
分 
時 
月中的天 
月 
週中的天 
年(可選項)

例如: “0 0 12 ? * WED” 表示 “個星期三的12點”

單個子表示式可以包含範圍和/或列表,例如:

"0 0 7 ? * MON-FRI" 表示 "每個工作日的7點"

"0 0 19 ? * MON,WED,FRI" 表示 "週一、週三和週五的19點"

"0 0 14 ? * MON-WED,SAT" 表示 "週一到週三以及週六的14點"

Cron表示式的規則說明
所有欄位都有一組可以指定的有效值。

數字 0 到 59 可以表示秒和分
0到23可以表示小時
月中的天可以使用1到31的數值, 但是你要注意該月的天數!
月用0 到 11之間的數值表示, 或者使用JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV 和 DEC來表示1-12月
一週中的天試用1到7表示 (1 表示 週日) 或者使用 SUN, MON, TUE, WED, THU, FRI 和 SAT


建立CronTrigger


CronTrigger例項使用TriggerBuilder 和 CronScheduleBuilder建立,靜態引入:

import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DateBuilder.*:



建立一個8到17點間每兩分鐘執行一次的Cron觸發器:

cronTrigger1 = newTrigger()
                .withIdentity("trigger3", "group1")
                .withSchedule(cronSchedule("0 0/2 8-17 * * ?"))
                .forJob("myJob", "group1")
                .build();


建立一個每天10:42執行的Cron觸發器:

 

cronTrigger2 = newTrigger()
                .withIdentity("trigger3", "group1")
                .withSchedule(dailyAtHourAndMinute(10, 42))
                .forJob(job.getKey())
                .build();

/*或者
 *我更喜歡下面這種方式
*/
cronTrigger3 = newTrigger()
                .withIdentity("trigger3", "group1")
                .withSchedule(cronSchedule("0 42 10 * * ?"))
                .forJob(job.getKey())
                .build();


關於CronTrigger”熄火”的指令


CronTrigger同樣包含一些指令在它”熄火”時可以告知Quartz怎麼去處理。

MISFIRE_INSTRUCTION_FIRE_ONCE_NOW - 如果熄火,該指令會告訴Quartz希望馬上再次觸發
MISFIRE_INSTRUCTION_DO_NOTHING - 如果熄火,該指令會告訴Quartz下一次執行時間到來時再執行,並不想馬上執行
cronTrigger4MisfireInstruction = newTrigger()
                        .withIdentity("trigger3", "group1")
                        .withSchedule(cronSchedule("0 0/2 8-17 * * ?")
                            .withMisfireHandlingInstructionFireAndProceed())
                        .forJob("myJob", "group1")
                        .build();


史上最詳細的Cron表示式的舉例講解
這裡列舉很多最常用的Cron表示式例子,拿來即用,使用時注意區別:

0 0 12 * * ?        每天12點執行
0 15 10 ? * *       每天的10:15執行
0 15 10 * * ?       每天的10:15執行
0 15 10 * * ? *     每天的10:15執行
0 15 10 * * ? 2005  2005年每天的10:15執行
0 * 14 * * ?        每天的14:00到14:59期間每分鐘執行
0 0/5 14 * * ?      每天的14:00到14:55每隔5分鐘執行
0 0/5 14,18 * * ?   每天的14:00到14:55每隔5分鐘執行和18:00到18:55每隔5分鐘執行
0 0-5 14 * * ?      每天的14:00到14:05執行
0 10,44 14 ? 3 WED  三月的每一個週三的14:10和14:44執行
0 15 10 ? * MON-FRI 工作日每天的10:15:00執行
0 15 10 15 * ?      每個月的第15天的10:15:00執行
0 15 10 L * ?       每個月最後一天的10:15:00執行
0 15 10 ? * 6L      每個月最後一個週五的10:15:00執行
0 15 10 ? * 6L 2002-2005    2002, 2003, 2004, 和2005年每個月最後一個週五的10:15:00執行
0 15 10 ? * 6#3     每個月的第三個週五的10:15:00執行
0 0 12 1/5 * ?      每個月的第一天的12:00:00開始執行,每隔5天間隔執行
0 11 11 11 11 ?     每年的11月11日11:11:00執行