關於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執行