下載和安裝
如果是采用maven管理依賴,則依賴配置如下:
- <dependency>
- <groupId>org.quartz-scheduler</groupId>
- <artifactId>quartz</artifactId>
- <version>2.2.3</version>
- </dependency>
- <dependency>
- <groupId>org.quartz-scheduler</groupId>
- <artifactId>quartz-jobs</artifactId>
- <version>2.2.3</version>
- </dependency>
如果不是的話,所需依賴包可以到官網(wǎng)下載http://www./downloads/
關(guān)鍵接口
Scheduler
一個(gè)scheduler的生命周期是有限的,從通過SchedulerFactory創(chuàng)建開始直到調(diào)用它的shutdown()方法。scheduler接口一旦創(chuàng)建,就能添加、移除、和列出job和trigger,并執(zhí)行另一些與調(diào)度相關(guān)的操作(例如暫停trigger),然而,在scheduler被start()方法啟動(dòng)前,它不會(huì)作用于任何trigger(執(zhí)行job)。
Job
一個(gè)job就是實(shí)現(xiàn)了Job接口的類。如下所示,這個(gè)接口只有一個(gè)簡單的方法:
- package org.quartz;
-
- public interface Job {
-
- public void execute(JobExecutionContext context)
- throws JobExecutionException;
- }
JobExecutionContext對(duì)象就是通過這個(gè)方法提供job實(shí)例的信息,如運(yùn)行環(huán)境,包括scheduler執(zhí)行的句柄,trigger觸發(fā)執(zhí)行的句柄,job的JobDetail對(duì)象,和一些其它信息。
JobDetail
JobDetail對(duì)象由Quartz客戶端(你的程序)在job添加進(jìn)scheduler的時(shí)候創(chuàng)建。這個(gè)對(duì)象包含了很多job的屬性設(shè)置,和JobDataMap一樣,它能夠存儲(chǔ)你的job實(shí)例的狀態(tài)信息。JobDetail對(duì)象本質(zhì)上是定義的job實(shí)例。
Trigger
trigger對(duì)象常常用于觸發(fā)job的執(zhí)行(或者觸發(fā)),當(dāng)你希望安排一個(gè)job,你可以實(shí)例化一個(gè)trigger,并調(diào)整其屬性來提供你想要的調(diào)度。trigger可能有一個(gè)與它們關(guān)聯(lián)的JobDataMap對(duì)象。JobDataMap用于傳遞特定于觸發(fā)器觸發(fā)的工作參數(shù)。Quartz附帶一些不同的觸發(fā)類型,但是最常用的就是SimpleTrigger和CronTrigger。
SimpleTrigger很方便,如果你需要一次性執(zhí)行(只是在一個(gè)給定時(shí)刻執(zhí)行job),或者如果你需要一個(gè)job在一個(gè)給定的時(shí)間,并讓它重復(fù)N次,并在執(zhí)行之間延遲T。
CronTrigger是有用的,如果你想擁有引發(fā)基于當(dāng)前日歷時(shí)間表,如每個(gè)星期五,中午或在每個(gè)月的第十天 10:15。
JobBuilder
用于定義/構(gòu)建已經(jīng)定義了Job實(shí)例的JobDetail實(shí)例。
TriggerBuilder
用于定義/構(gòu)建Trigger實(shí)例。
特性
當(dāng)job和trigger被登記到Quartz scheduler時(shí)給出了identifying key。Job和trigger(JobKey和TriggerKey)的key允許它們被放置到group中,group可用于分類組織job和trigger,例如“報(bào)表job”和“維護(hù)job”。Job或者trigger的identifying key值的name部分在group中必須是唯一的。換句話說,job或trigger的完整的identifying key是由name和group組成。
第一個(gè)quartz 程序
- import org.quartz.Job;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobExecutionException;
-
- import java.util.Date;
-
- public class HelloJob implements Job {
-
- /**
- * 需要一個(gè)無參的public構(gòu)造以便scheduler在它需要的時(shí)候可以實(shí)例化這個(gè)class.
- */
- public HelloJob() {
- }
-
-
- /**
- * 要執(zhí)行的代碼
- *
- * @param context JobExecutionContext
- * @throws JobExecutionException
- */
- public void execute(JobExecutionContext context) throws JobExecutionException {
- System.out.println("Hello World! - " + new Date());
- }
- }
- import org.quartz.DateBuilder;
- import org.quartz.JobBuilder;
- import org.quartz.JobDetail;
- import org.quartz.Scheduler;
- import org.quartz.SchedulerFactory;
- import org.quartz.Trigger;
- import org.quartz.TriggerBuilder;
- import org.quartz.impl.StdSchedulerFactory;
-
- import java.util.Date;
-
- public class SimpleExample {
-
- public void run() throws Exception {
-
- System.out.println("------- 初始化 ----------------------");
-
- // 首先要實(shí)例化scheduler
- SchedulerFactory schedulerFactory = new StdSchedulerFactory();
- Scheduler scheduler = schedulerFactory.getScheduler();
-
- System.out.println("------- 初始化完成 -----------");
-
- // 獲取給定時(shí)間的下一個(gè)完整分鐘的時(shí)間,例如給定時(shí)間 08:13:54 則會(huì)反回 08:14:00
- Date runTime = DateBuilder.evenMinuteDate(new Date());
-
- System.out.println("------- Job安排 -------------------");
-
- // 獲取job實(shí)例
- JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
-
- // 在下一輪分鐘觸發(fā)運(yùn)行
- Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startAt(runTime).build();
-
- // 告訴quartz使用某個(gè)trigger執(zhí)行某個(gè)job
- scheduler.scheduleJob(job, trigger);
- System.out.println(job.getKey() + " 將會(huì)運(yùn)行于: " + runTime);
-
- // 啟動(dòng)scheduler
- scheduler.start();
-
- System.out.println("------- 開始安排 -----------------");
-
- System.out.println("------- 等待65秒 -------------");
- Thread.sleep(65L * 1000L);
-
- // 關(guān)閉scheduler
- System.out.println("------- 關(guān)閉 ---------------------");
- scheduler.shutdown(true);
- System.out.println("------- 關(guān)閉完成 -----------------");
- }
-
- public static void main(String[] args) throws Exception {
- SimpleExample example = new SimpleExample();
- example.run();
- }
- }
更多關(guān)于Job and JobDetail
我們給scheduler一個(gè)JobDetail實(shí)例,它知道要執(zhí)行的job的類型,只需提供我們構(gòu)建JobDetail的job類。每次scheduler執(zhí)行job,它會(huì)在調(diào)用它的execute(..)方法之前創(chuàng)建這個(gè)類的新實(shí)例。當(dāng)執(zhí)行完成,job實(shí)例的引用被刪除,然后垃圾收集器回收實(shí)例。這種行為的后果之一是job必須有一個(gè)無參數(shù)的構(gòu)造函數(shù)(當(dāng)使用默認(rèn)JobFactory實(shí)現(xiàn)),另一個(gè)是在job類上定義狀態(tài)數(shù)據(jù)字段沒有意義,它們的值在Job執(zhí)行期間不會(huì)被保存。你可能現(xiàn)在想問,我如何為一個(gè)job實(shí)例提供屬性或者配置?我如何在執(zhí)行job期間追蹤狀態(tài)?
答案就是JobDataMap,它是JobDetail對(duì)象的一部分。
JobDataMap
JobDataMap可以用來保存大量那些在job實(shí)例執(zhí)行時(shí)你希望得到的 (序列化)數(shù)據(jù)對(duì)象。JobDataMap是Java Map接口的一個(gè)實(shí)現(xiàn),并且添加一些便利的方法來存儲(chǔ)和檢索數(shù)據(jù)的原始類型。
存放數(shù)據(jù)
- JobDetail job = newJob(DumbJob.class)
- .withIdentity("myJob", "group1") // name "myJob", group "group1"
- .usingJobData("jobSays", "Hello World!")
- .usingJobData("myFloatValue", 3.141f)
- .build();
獲取數(shù)據(jù)
- public class DumbJob implements Job {
-
- public DumbJob() {
- }
-
- public void execute(JobExecutionContext context)
- throws JobExecutionException
- {
- JobKey key = context.getJobDetail().getKey();
-
- JobDataMap dataMap = context.getJobDetail().getJobDataMap();
-
- String jobSays = dataMap.getString("jobSays");
- float myFloatValue = dataMap.getFloat("myFloatValue");
-
- System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
- }
- }
trigger也可以有與他們有關(guān)的JobDataMap,例如TriggerBuilder.newTrigger().usingJobData。
JobDataMap dataMap = context.getMergedJobDataMap()。這個(gè)可以獲取到j(luò)obDetail和trigger上的所有數(shù)據(jù),trigger上相同名字的值將覆蓋前者。
更多關(guān)于trigger
通用的trigger屬性
屬性jobKey是trigger啟動(dòng)時(shí)將要執(zhí)行的job的標(biāo)識(shí)。
startTime是trigger第一次生效的時(shí)間。值是一個(gè)java.util.Date對(duì)象,定義了一個(gè)給定的日期時(shí)間。對(duì)于一些類型的trigger來說,trigger會(huì)在這個(gè)時(shí)間準(zhǔn)確啟動(dòng)。對(duì)于其它類型來說僅僅標(biāo)志著時(shí)間表開始被跟蹤。這意味著你可以這樣存儲(chǔ)一個(gè)schedule的trigger,例如一月“每月的第5天執(zhí)行”,如果startTime屬性設(shè)置為4月1日,在首次觸發(fā)前,還要過幾個(gè)月。
endTime屬性表示trigger的計(jì)劃不再有效。換句話說,一個(gè)“每月5號(hào)”的trigger,endTime為7月1號(hào),它上次執(zhí)行的時(shí)間就是6月5號(hào)。
優(yōu)先級(jí)
有時(shí),當(dāng)你有很多觸發(fā)器(或者你得Quartz線程池有很多工作線程),Quartz也許沒有足夠的資源在同一時(shí)間觸發(fā)所有的trigger。這種情況下,你也許想控制你的哪些觸發(fā)器可以優(yōu)先獲得Quartz的工作線程。為此,你需要設(shè)置trigger的優(yōu)先級(jí)屬性。如果N個(gè)觸發(fā)器同一時(shí)間觸發(fā),但是當(dāng)前僅有Z和可用的工作線程,前Z個(gè)具有高優(yōu)先級(jí)的觸發(fā)器將首先執(zhí)行。任何整數(shù),正數(shù)或者負(fù)數(shù)都允許作為優(yōu)先級(jí)。如果你的trigger沒有設(shè)定優(yōu)先級(jí)它將使用默認(rèn)的優(yōu)先級(jí)為5。
注意:優(yōu)先級(jí)僅僅在同一時(shí)間觸發(fā)的trigger中才有效。一個(gè)在10:59觸發(fā)的trigger將永遠(yuǎn)比在11:00觸發(fā)的trigger先執(zhí)行。
注意:當(dāng)觸發(fā)器被監(jiān)測到需要恢復(fù)時(shí),它的優(yōu)先級(jí)將與原始的優(yōu)先級(jí)相同。
觸發(fā)失敗說明
Trigger另一個(gè)重要的屬性就是“過時(shí)觸發(fā)指令”。如果因?yàn)楫?dāng)前scheduler被關(guān)閉或者Quartz的線程池沒有可用的線程用來執(zhí)行job導(dǎo)致當(dāng)前的觸發(fā)器錯(cuò)過了觸發(fā)時(shí)間,就是出現(xiàn)錯(cuò)誤。不同類型的trigger有不同的失敗處理方式。默認(rèn)情況下,它們使用“智能策略”,其擁有基于trigger類型和配置的動(dòng)態(tài)行為。Scheduler啟動(dòng)時(shí),它將搜索所有失敗的持久化的trigger,然后基于它們的失敗配置來更新它們。
日歷
Quartz日歷對(duì)象(不是java.util.Calendar對(duì)象)能夠與在scheduler中定義和存儲(chǔ)的trigger時(shí)間相關(guān)聯(lián)。日歷可用于從trigger的觸發(fā)計(jì)劃中排除某些時(shí)間。例如,你可以創(chuàng)建一個(gè)trigger在工作日的9:30觸發(fā),但是排除法定假日。日歷可以使任何實(shí)現(xiàn)了org.quartz.Calendar接口的序列化對(duì)象。注意這些方法的參數(shù)類型是long。這是毫秒的時(shí)間戳格式。這意味著日歷可以“阻擋”精確至一毫秒的時(shí)間。最有可能的是你會(huì)對(duì)“屏蔽”一整天感興趣。Quartz包括一個(gè)org.quartz.impl.HolidayCalendar就是干這個(gè)的,非常方便。
日歷必須通過addCalendar(..)方法實(shí)例化并注冊(cè)到scheduler中。如果你使用HolidayCalendar,實(shí)例化之后,你應(yīng)該使用它的addExcludedDate(Date date)方法將你想排除在調(diào)度器之外的日期添加進(jìn)去。同一個(gè)日歷實(shí)例可以被多個(gè)trigger使用,如下所示:
- HolidayCalendar cal = new HolidayCalendar();
- cal.addExcludedDate( someDate );
- cal.addExcludedDate( someOtherDate );
-
- sched.addCalendar("myHolidays", cal, false,false);
-
-
- Trigger t = newTrigger()
- .withIdentity("myTrigger")
- .forJob("myJob")
- .withSchedule(dailyAtHourAndMinute(9, 30)) // execute job daily at 9:30
- .modifiedByCalendar("myHolidays") // but not on holidays
- .build();
-
- // .. schedule job with trigger
-
- Trigger t2 = newTrigger()
- .withIdentity("myTrigger2")
- .forJob("myJob2")
- .withSchedule(dailyAtHourAndMinute(11, 30)) // execute job daily at 11:30
- .modifiedByCalendar("myHolidays") // but not on holidays
- .build();
-
- // .. schedule job with trigger2
上面的代碼創(chuàng)建了兩個(gè)觸發(fā)器,每天都會(huì)執(zhí)行。然而,任何發(fā)生在排除日歷的觸發(fā)將被跳過。org.quartz.impl.calendar包提供了許多Calendar的實(shí)現(xiàn),也許可以滿足你的需求。
addCalendar(String calName,
Calendar calendar,
boolean replace,
boolean updateTriggers)
throws SchedulerException
第一個(gè)參數(shù)是日歷名稱
第二個(gè)參數(shù)是日歷實(shí)例
第三個(gè)參數(shù)是是否替換,如果日歷名稱重復(fù)但是replace為false,那么會(huì)報(bào)異常
第四個(gè)參數(shù)是是否更新引用了已經(jīng)存在的日歷的trigger,以便使scheduler基于正確的trigger
SimpleTrigger
如果你需要一個(gè)job在特定的時(shí)間執(zhí)行一次或者在特定的時(shí)間,以特定的間隔執(zhí)行多次SimpleTrigger能夠滿足你的需求。例如:你想讓一個(gè)trigger在2015年1月13號(hào)11:23:54分觸發(fā),或者你想在那個(gè)時(shí)間執(zhí)行,執(zhí)行5次,每10秒一次。這樣描述,你也許不難發(fā)現(xiàn)SimpleTrigger的屬性:開始時(shí)間,結(jié)束時(shí)間,重復(fù)次數(shù),重復(fù)間隔。所有這些屬性正是你期望的,只有一組與結(jié)束時(shí)間關(guān)聯(lián)的特殊屬性。
重復(fù)的次數(shù)可以是0,正數(shù)或者常數(shù)SimpleTrigger.REPEAT_INDEFINITELY。重復(fù)的間隔屬性必須是0或一個(gè)正的長整型,代表毫秒值。注意,間隔為0將導(dǎo)致觸發(fā)器同時(shí)觸發(fā)“重復(fù)次數(shù)”這么多次(盡可能接近scheduler的并發(fā)管理數(shù))。
如果你還不熟悉Quartz的DateBuilder類,你可能發(fā)現(xiàn)依賴于你的開始時(shí)間(或結(jié)束時(shí)間)計(jì)算trigger的觸發(fā)次數(shù)很有幫助。
endTIme屬性會(huì)計(jì)算并重寫先前設(shè)置的重復(fù)次數(shù)的屬性。如果你想創(chuàng)建一個(gè)每10秒觸發(fā)一次的trigger直到一個(gè)給定的時(shí)刻,這也許會(huì)有用,而不必計(jì)算開始時(shí)間和結(jié)束時(shí)間間的重復(fù)次數(shù),你可以簡單的指出結(jié)束時(shí)間然后使用REPEAT_INDEFINITELY表明重復(fù)次數(shù)(你甚至可以指定較大的重復(fù)次數(shù)超過在結(jié)束時(shí)間到達(dá)之前trigger觸發(fā)的次數(shù))。SimpleTrigger實(shí)例通過使用TriggerBuilder(創(chuàng)建trigger的主屬性)和SimpleScheduleBuilder(創(chuàng)建SimpleTrigger特殊屬性)創(chuàng)建。
注意:如果你不顯示的設(shè)置屬性TriggerBuilder(和其它的quartz創(chuàng)建者)會(huì)選取一個(gè)合理的值。例如,如果你不調(diào)用withIdentity(..)的某個(gè)方法,TriggerBuilder將為你的trigger生成一個(gè)隨機(jī)的名字,同樣,如果你沒有調(diào)用startAt(..),則設(shè)定為當(dāng)前的時(shí)間(立即執(zhí)行)。
首先靜態(tài)引入:
- import static org.quartz.TriggerBuilder.*;
- import static org.quartz.SimpleScheduleBuilder.*;
- import static org.quartz.DateBuilder.*:
創(chuàng)建一個(gè)指定時(shí)間執(zhí)行的trigger,沒有重復(fù)次數(shù)
- SimpleTrigger trigger = (SimpleTrigger) newTrigger()
- .withIdentity("trigger1", "group1")
- .startAt(myStartTime) // some Date
- .forJob("job1", "group1") // identify job with name, group strings
- .build();
在指定的時(shí)間創(chuàng)建一個(gè)trigger,然后每10秒觸發(fā)一次,共觸發(fā)10次
- 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();
創(chuàng)建一個(gè)觸發(fā)一次的trigger,5分鐘后觸發(fā)
- trigger = (SimpleTrigger) newTrigger()
- .withIdentity("trigger5", "group1")
- .startAt(futureDate(5, IntervalUnit.MINUTE)) // use DateBuilder to create a date in the future
- .forJob(myJobKey) // identify job with its JobKey
- .build();
創(chuàng)建一個(gè)立即觸發(fā)的trigger,每5分鐘觸發(fā)一次,直到22:00結(jié)束
- trigger = newTrigger()
- .withIdentity("trigger7", "group1")
- .withSchedule(simpleSchedule()
- .withIntervalInMinutes(5)
- .repeatForever())
- .endAt(dateOf(22, 0, 0))
- .build();
建立一個(gè)trigger,每小時(shí)開始的時(shí)候觸發(fā),每2小時(shí)出發(fā)一次,直到永遠(yuǎn)
- trigger = newTrigger()
- .withIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
- .startAt(evenHourDate(null)) // get the next even-hour (minutes and seconds zero ("00:00"))
- .withSchedule(simpleSchedule()
- .withIntervalInHours(2)
- .repeatForever())
- // note that in this example, 'forJob(..)' is not called
- // - which is valid if the trigger is passed to the scheduler along with the job
- .build();
-
- scheduler.scheduleJob(trigger, job);
SimpleTrigger有幾個(gè)指令,用來通知quartz當(dāng)觸發(fā)失敗該怎么做。這些指令被SimpleTrigger自己定義。這些常量包括:
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_FIRE_NOW
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT
所有的trigger都有MISFIRE_INSTRUCTION_SMART_POLICY屬性可以使用,這個(gè)指定對(duì)所有的觸發(fā)器類型都是可用的。
如果使用“智能策略”,SimpleTrigger會(huì)基于給定SimpleTrigger實(shí)例的配置和狀態(tài)動(dòng)態(tài)地選擇觸發(fā)的失敗指令。SimpleTrigger.updateAfterMisfire()方法的Javadoc解釋了這些動(dòng)態(tài)行為的細(xì)節(jié)。也可以在創(chuàng)建SimpleTrigger時(shí),指定失敗指令作為簡單scheduler的一部分。
- trigger = newTrigger()
- .withIdentity("trigger7", "group1")
- .withSchedule(simpleSchedule()
- .withIntervalInMinutes(5)
- .repeatForever()
- .withMisfireHandlingInstructionNextWithExistingCount())
- .build();
CronTrigger
Cron是一個(gè)UNIX工具,已經(jīng)存在了很長時(shí)間,所以它的調(diào)度功能強(qiáng)大且得到證實(shí)。CronTrigger使用“cron表達(dá)式”。
如果你需要基于類似日歷的觀念反復(fù)觸發(fā)一個(gè)job,而不是使用SimpleTrigger指定一個(gè)固定的時(shí)間間隔,相對(duì)于SimpleTrigger,CronTrigger往往更有用。
使用CronTrigger,你可以指定一個(gè)觸發(fā)計(jì)劃例如“每周五的中午”,或者“每個(gè)工作日上午9:00”,甚至“1月的周一,周三和周五早上9:00至10:00每五分鐘”。
即便如此,和SimpleTrigger一樣, CronTrigger也有一個(gè)startTime指定計(jì)劃的生效時(shí)間也有一個(gè)(可選的)endTime指定計(jì)劃的停止時(shí)間。
Cron表達(dá)式
Cron表達(dá)式用于CronTrigger實(shí)例的配置。Cron表達(dá)式實(shí)際上是由7個(gè)子表達(dá)式組成,包括秒、分、時(shí)、每月的第幾天、月、每周的第幾天、年(可選字段),用來描述計(jì)劃安排的細(xì)節(jié)。這些子表達(dá)式使用空格分割。一個(gè)完整的cron表達(dá)式是一個(gè)像這樣的字符串“0 0 12 ? WED *”——這代表著“每周三的12:00”。每個(gè)子表達(dá)式都能包含范圍/或列表,例如前面每周的第幾天(“WED”)可以替換成“MON-FRI”,“ MON,WED,FRI”,甚至“MON-WED,SAT”。
*
用來選擇一個(gè)字段上的所有值。例如:分鐘字段上的“*”表示“每分鐘”。
?
當(dāng)你需要在允許的兩個(gè)字段中的一個(gè)指定一些值的時(shí)候使用。例如,你想讓你得trigger在每月的某一天觸發(fā)(假如,10號(hào)),但是不關(guān)系在周幾發(fā)生,你應(yīng)該在每月的第幾天字段上設(shè)置“10”,在每周的第幾天字段上設(shè)置“?”。具體參見下面實(shí)例。
-
用于指定范圍。例如,小時(shí)字段上設(shè)置“10-12”表示“10點(diǎn),11點(diǎn),12點(diǎn)”。
,
用于指定額外的值。例如,在每周的第幾天設(shè)置“MON,WED,FRI”表示“周一,周三,周五”。
/
用于指定增量。例如,秒字段上“0/15”表示“0秒,15秒,30秒,45秒”。秒字段上“5/15”表示“5秒,20秒,35秒,50秒”,每月中的第幾天設(shè)置“1/3”表示“從每月的第一天開始每3天觸發(fā)一次”。
L
“l(fā)ast”簡寫,可用在兩個(gè)字段,每個(gè)字段的含義不同。例如,“L”在每月的第幾天字段上指的是“每月的最后一天”——1月31號(hào),和非閏年的2月28號(hào)。如果用在每周的第幾天,就是“7”或者“SAT”的意思。但是如果用在每周第幾天的一個(gè)值后面,就意味著“每月最后一個(gè)星期的第幾天”——例如“6L”表示“每月最后一個(gè)周五”。你還可以為每月的最后一天指定一個(gè)偏移量,例如“L-3”意味著每月倒數(shù)第三天。當(dāng)使用“L”選項(xiàng)時(shí),重要的是不要指定列表或范圍值,不然你將得到混亂/不期望的結(jié)果。
W
用來指定距離指定日期最近的工作日(周一至周五)。例如,如果你指定了“15W”在每月第幾天的字段上,表示:“離本月15號(hào)最近的工作日”。所以,如果15號(hào)是周六,trigger將在14號(hào)周五觸發(fā),如果15號(hào)是周日,trigger將在16號(hào)周一觸發(fā),如果15號(hào)是周二,trigger將在15號(hào)周二觸發(fā)。然而如果在每月的第幾天字段指定“1W”,而且1號(hào)是周六,trigger將會(huì)在3號(hào)周一觸發(fā),它不會(huì)跳過月的邊界?!癢”只能指定每月第幾天字段中的一天,不能指定一個(gè)范圍或列表。
“L”和“W”字符也可以在每月的第幾天字段組合成“LW”,表示“每月的最后一個(gè)工作日”。
#
用于指定每月中的第幾個(gè)周幾。例如,每周第幾天字段上的“6#3”表示“每月的第3個(gè)周五”(”6“=周五,”#3“=每月的第3個(gè))。另一個(gè)例子:”2#1“=每月的第1個(gè)周一,”4#5“每月的第5個(gè)周三。注意,如果你指定”#5”,但是該月沒有第5個(gè)這一周的天數(shù),觸發(fā)器將不會(huì)執(zhí)行。
注意:月份的英文名和周幾的英文是不區(qū)分大小寫的。MON與mon都是合法的字符。
表達(dá)式
|
含義
|
0 0 12 * * ?
|
每天12:00觸發(fā)
|
0 15 10 ? * *
|
每天10:15觸發(fā)
|
0 15 10 * * ?
|
每天10:15觸發(fā)
|
0 15 10 * * ? *
|
每天10:15觸發(fā)
|
0 15 10 * * ? 2005
|
2005年的每天10:15觸發(fā)
|
0 * 14 * * ?
|
每天14:00至14:59每分鐘觸發(fā)
|
0 0/5 14 * * ?
|
每天14:00開始至14:55每5分鐘觸發(fā)
|
0 0/5 14,18 * * ?
|
每天14:00開始至14:55每5分鐘觸發(fā),18:00開始至18:55每5分鐘觸發(fā)
|
0 0-5 14 * * ?
|
每天14:00開始至14:05每分鐘觸發(fā)
|
0 10,44 14 ? 3 WED
|
三月份的每個(gè)周三14:10和14:44觸發(fā)
|
0 15 10 ? * MON-FRI
|
每個(gè)周一至周五上午10:15觸發(fā)
|
0 15 10 15 * ?
|
每月15號(hào)10:15觸發(fā)
|
0 15 10 L * ?
|
每月最后一天10:15觸發(fā)
|
0 15 10 L-2 * ?
|
每月倒數(shù)第2天10:15觸發(fā)
|
0 15 10 ? * 6L
|
每月最后一個(gè)周五10:15觸發(fā)
|
0 15 10 ? * 6L 2002-2005
|
2002年至2005年每月最后一個(gè)周五10:15觸發(fā)
|
0 15 10 ? * 6#3
|
每月第3個(gè)周五10:15觸發(fā)
|
0 0 12 1/5 * ?
|
每月的第一天開始,每個(gè)第5天12:00觸發(fā)
|
0 11 11 11 11 ?
|
每年11月11號(hào)11:11觸發(fā)
|
注意:當(dāng)不指定一周中的第幾天和一月中的第幾天,你必須在這兩個(gè)字段之一使用”?”。
首先靜態(tài)導(dǎo)入:
- import static org.quartz.TriggerBuilder.*;
- import static org.quartz.CronScheduleBuilder.*;
- import static org.quartz.DateBuilder.*:
- trigger = new Trigger()
- .withIdentity("trigger3", "group1")
- .withSchedule(cronSchedule("0 42 10 ? * WED"))
- .inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
- .forJob(myJobKey)
- .build();
CronTrigger失敗說明
下面的說明可以在CronTrigger失敗時(shí)用來介紹Quartz信息。這些介紹是CronTrigger自己定義的常量。包括:
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_DO_NOTHING
MISFIRE_INSTRUCTION_FIRE_NOW
所有的trigger都有MISFIRE_INSTRUCTION_SMART_POLICY說明可供使用,這個(gè)說明也是所有trigger類型默認(rèn)的?!敝悄懿呗訡ronTrigger解讀為“MISFIRE_INSTRUCTION_FIRE_NOW。CronTrigger.updateAfterMisfire()方法的Javadoc解析了這些行為的細(xì)節(jié)。
在構(gòu)建CronTrigger時(shí),你可以指定簡單schedule的失敗說明。
- trigger = newTrigger()
- .withIdentity("trigger3", "group1")
- .withSchedule(cronSchedule("0 0/2 8-17 * * ?")
- ..withMisfireHandlingInstructionFireAndProceed())
- .forJob("myJob", "group1")
- .build();
使用TriggerListener和JobListener
TriggerListener和JobListener
監(jiān)聽器是你基于scheduler中事件的活動(dòng)創(chuàng)建的對(duì)象。就像它們名字所示,TriggerListener接收與trigger有關(guān)的事件,JobListener接收與Job有關(guān)的事件。
與trigger有關(guān)的事件包括trigger觸發(fā),trigger觸發(fā)失敗,trigger執(zhí)行完成(trigger完成job執(zhí)行完畢)。
org.quartz.TriggerListener接口
- publicinterface TriggerListener {
- public String getName();
-
- publicvoid triggerFired(Trigger trigger, JobExecutionContext context);
-
- publicboolean vetoJobExecution(Trigger trigger, JobExecutionContext context);
-
- publicvoid triggerMisfired(Trigger trigger);
-
- publicvoid triggerComplete(Trigger trigger, JobExecutionContext context, inttriggerInstructionCode);
- }
與job有關(guān)的時(shí)間包括:job即將進(jìn)行的通知,和job已經(jīng)完成的通知。
org.quartz.JobListener接口
- publicinterface JobListener {
- public String getName();
-
- publicvoid jobToBeExecuted(JobExecutionContext context);
-
- publicvoid jobExecutionVetoed(JobExecutionContext context);
-
- publicvoid jobWasExecuted(JobExecutionContext context, JobExecutionException jobException);
- }
創(chuàng)建你自己的監(jiān)聽器
要?jiǎng)?chuàng)建一個(gè)監(jiān)聽器,需要簡單創(chuàng)建一個(gè)實(shí)現(xiàn)org.quartz.TriggerListener接口或/和org.quartz.JobListener接口的對(duì)象。然后在運(yùn)行時(shí)監(jiān)聽器被注冊(cè)到scheduler中,并且必須給定一個(gè)name(或者確切的說,它們必須能夠通過它們的getName()方法給出它們的名字)。為了你的方便,而不需要實(shí)現(xiàn)這些接口,你的類還可以繼承JobListenerSupport或TriggerListenerSupport并簡單的重寫你感興趣的方法。監(jiān)聽器被注冊(cè)到scheduler的ListenerManager
。
注意:監(jiān)聽器在運(yùn)行時(shí)被注冊(cè)到scheduler,而不是一直隨job和trigger存儲(chǔ)在JobStore中。這是因?yàn)楸O(jiān)聽器通常作為你的應(yīng)用程序的一個(gè)集成點(diǎn)。因此,你的應(yīng)用每次運(yùn)行,監(jiān)聽器都需要重新注冊(cè)進(jìn)scheduler。
下面的示例演示了將感興趣的JobListener添加進(jìn)不同類型的job中。以同樣的方式添加可用的TriggerListener。
添加一個(gè)感興趣的JobListener到特定的job
scheduler.getListenerManager().addJobListener(myJobListener,KeyMatcher.jobKeyEquals(new JobKey("myJobName", "myJobGroup")));
你可能想使用靜態(tài)導(dǎo)入導(dǎo)入matcher和key類,這將使你清晰的匹配matcher:
import static org.quartz.JobKey.*;
import static org.quartz.impl.matchers.KeyMatcher.*;
import static org.quartz.impl.matchers.GroupMatcher.*;
import static org.quartz.impl.matchers.AndMatcher.*;
import static org.quartz.impl.matchers.OrMatcher.*;
import static org.quartz.impl.matchers.EverythingMatcher.*;
...etc.
上面的例子將變成:
scheduler.getListenerManager().addJobListener(myJobListener,jobKeyEquals(jobKey("myJobName", "myJobGroup")));
添加一個(gè)感興趣的JobListener到一個(gè)指定group的所有job
scheduler.getListenerManager().addJobListener(myJobListener, jobGroupEquals("myJobGroup"));
添加一個(gè)感興趣的JobListener到兩個(gè)指定的group的所有job
scheduler.getListenerManager().addJobListener(myJobListener, or(jobGroupEquals("myJobGroup"), jobGroupEquals("yourGroup")));
添加一個(gè)感興趣的JobListener到所有job
scheduler.getListenerManager().addJobListener(myJobListener, allJobs());
使用SchedulerListener
SchedulerListener
SchedulerListener和TriggerListener及JobListener很像,除了其接收Scheduler自身事件的通知,而不必與特定的trigger和job相關(guān)聯(lián)。在大量的其他事件中,Scheduler關(guān)聯(lián)的事件包括:
添加一個(gè)job或trigger
移除一個(gè)trigger或job
Schduler中的一系列錯(cuò)誤
Schduler的關(guān)閉
SchdulerListner可以是任何實(shí)現(xiàn)org.quartz.SchedulerListener接口的對(duì)象。
配置
quartz使用quartz.properties文件來配置。它必須位于classpath上。例如:
- #============================================================================
- # Configure Main Scheduler Properties
- #============================================================================
-
- org.quartz.scheduler.instanceName: TestScheduler
- org.quartz.scheduler.instanceId: AUTO
-
- org.quartz.scheduler.skipUpdateCheck: true
-
- #============================================================================
- # Configure ThreadPool
- #============================================================================
-
- org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
- org.quartz.threadPool.threadCount: 3
- org.quartz.threadPool.threadPriority: 5
-
- #============================================================================
- # Configure JobStore
- #============================================================================
-
- org.quartz.jobStore.misfireThreshold: 60000
-
- org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
-
- #org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
- #org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
- #org.quartz.jobStore.useProperties: false
- #org.quartz.jobStore.dataSource: myDS
- #org.quartz.jobStore.tablePrefix: QRTZ_
- #org.quartz.jobStore.isClustered: false
-
- #============================================================================
- # Configure Datasources
- #============================================================================
-
- #org.quartz.dataSource.myDS.driver: org.postgresql.Driver
- #org.quartz.dataSource.myDS.URL: jdbc:postgresql://localhost/dev
- #org.quartz.dataSource.myDS.user: jhouse
- #org.quartz.dataSource.myDS.password:
- #org.quartz.dataSource.myDS.maxConnections: 5
-
-
-
- #============================================================================
- # Configure Plugins
- #============================================================================
-
- org.quartz.plugin.triggHistory.class: org.quartz.plugins.history.LoggingJobHistoryPlugin
-
- org.quartz.plugin.jobInitializer.class: org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
- org.quartz.plugin.jobInitializer.fileNames: quartz_data.xml
- org.quartz.plugin.jobInitializer.failOnFileNotFound: true
- org.quartz.plugin.jobInitializer.scanInterval: 120
- org.quartz.plugin.jobInitializer.wrapInUserTransaction: false
日志
Quartz使用SLF4J框架。
|