摘要:調(diào)度器就相當(dāng)于一個(gè)容器,裝載著任務(wù)和觸發(fā)器。用于指定額外的值。然而,如果指定并且第一號(hào)是星期六,那么觸發(fā)器的觸發(fā)在第三號(hào)周一,因?yàn)樗粫?huì)過(guò)一個(gè)月的日子的邊界。注意如果只是指定,則觸發(fā)器在月份中不會(huì)觸發(fā)。
1. Quartz 體系結(jié)構(gòu)版權(quán)聲明:本文由吳仙杰創(chuàng)作整理,轉(zhuǎn)載請(qǐng)注明出處:https://segmentfault.com/a/1190000009128277
Quartz 設(shè)計(jì)有三個(gè)核心類,分別是 Scheduler(調(diào)度器)Job(任務(wù))和 Trigger (觸發(fā)器),它們是我們使用 Quartz 的關(guān)鍵。
1)Job:定義需要執(zhí)行的任務(wù)。該類是一個(gè)接口,只定義一個(gè)方法 execute(JobExecutionContext context),在實(shí)現(xiàn)類的 execute 方法中編寫(xiě)所需要定時(shí)執(zhí)行的 Job(任務(wù)), JobExecutionContext 類提供了調(diào)度應(yīng)用的一些信息。Job 運(yùn)行時(shí)的信息保存在 JobDataMap 實(shí)例中。
2)Trigger:負(fù)責(zé)設(shè)置調(diào)度策略。該類是一個(gè)接口,描述觸發(fā) job 執(zhí)行的時(shí)間觸發(fā)規(guī)則。主要有 SimpleTrigger 和 CronTrigger 這兩個(gè)子類。當(dāng)且僅當(dāng)需調(diào)度一次或者以固定時(shí)間間隔周期執(zhí)行調(diào)度,SimpleTrigger 是最適合的選擇;而 CronTrigger 則可以通過(guò) Cron 表達(dá)式定義出各種復(fù)雜時(shí)間規(guī)則的調(diào)度方案:如工作日周一到周五的 15:00~16:00 執(zhí)行調(diào)度等。
3)Scheduler:調(diào)度器就相當(dāng)于一個(gè)容器,裝載著任務(wù)和觸發(fā)器。該類是一個(gè)接口,代表一個(gè) Quartz 的獨(dú)立運(yùn)行容器, Trigger 和 JobDetail 可以注冊(cè)到 Scheduler 中, 兩者在 Scheduler 中擁有各自的組及名稱, 組及名稱是 Scheduler 查找定位容器中某一對(duì)象的依據(jù), Trigger 的組及名稱必須唯一, JobDetail 的組和名稱也必須唯一(但可以和 Trigger 的組和名稱相同,因?yàn)樗鼈兪遣煌愋偷模cheduler 定義了多個(gè)接口方法, 允許外部通過(guò)組及名稱訪問(wèn)和控制容器中 Trigger 和 JobDetail。
Scheduler 可以將 Trigger 綁定到某一 JobDetail 中, 這樣當(dāng) Trigger 觸發(fā)時(shí), 對(duì)應(yīng)的 Job 就被執(zhí)行。一個(gè) Job 可以對(duì)應(yīng)多個(gè) Trigger, 但一個(gè) Trigger 只能對(duì)應(yīng)一個(gè) Job。可以通過(guò) SchedulerFactory 創(chuàng)建一個(gè) SchedulerFactory 實(shí)例。Scheduler 擁有一個(gè) SchedulerContext,它類似于 SchedulerContext,保存著 Scheduler 上下文信息,Job 和 Trigger 都可以訪問(wèn) SchedulerContext 內(nèi)的信息。SchedulerContext 內(nèi)部通過(guò)一個(gè) Map,以鍵值對(duì)的方式維護(hù)這些上下文數(shù)據(jù),SchedulerContext 為保存和獲取數(shù)據(jù)提供了多個(gè) put() 和 getXxx() 的方法。可以通過(guò) Scheduler#getContext() 獲取對(duì)應(yīng)的 SchedulerContext 實(shí)例。
4)JobDetail:描述 Job 的實(shí)現(xiàn)類及其它相關(guān)的靜態(tài)信息,如:Job 名字、描述、關(guān)聯(lián)監(jiān)聽(tīng)器等信息。Quartz 每次調(diào)度 Job 時(shí), 都重新創(chuàng)建一個(gè) Job 實(shí)例, 所以它不直接接受一個(gè) Job 的實(shí)例,相反它接收一個(gè) Job 實(shí)現(xiàn)類,以便運(yùn)行時(shí)通過(guò) newInstance() 的反射機(jī)制實(shí)例化 Job。
5)ThreadPool:Scheduler 使用一個(gè)線程池作為任務(wù)運(yùn)行的基礎(chǔ)設(shè)施,任務(wù)通過(guò)共享線程池中的線程提高運(yùn)行效率。
Job 有一個(gè) StatefulJob 子接口(Quartz 2 后用 @PersistJobDataAfterExecution 注解代替),代表有狀態(tài)的任務(wù),該接口是一個(gè)沒(méi)有方法的標(biāo)簽接口,其目的是讓 Quartz 知道任務(wù)的類型,以便采用不同的執(zhí)行方案。
無(wú)狀態(tài)任務(wù)在執(zhí)行時(shí)擁有自己的 JobDataMap 拷貝,對(duì) JobDataMap 的更改不會(huì)影響下次的執(zhí)行。
有狀態(tài)任務(wù)共享同一個(gè) JobDataMap 實(shí)例,每次任務(wù)執(zhí)行對(duì) JobDataMap 所做的更改會(huì)保存下來(lái),后面的執(zhí)行可以看到這個(gè)更改,也即每次執(zhí)行任務(wù)后都會(huì)對(duì)后面的執(zhí)行發(fā)生影響。
正因?yàn)檫@個(gè)原因,無(wú)狀態(tài)的 Job 能并發(fā)執(zhí)行,而有狀態(tài)的 StatefulJob 不能并發(fā)執(zhí)行。這意味著如果前次的 StatefulJob 還沒(méi)有執(zhí)行完畢,下一次的任務(wù)將阻塞等待,直到前次任務(wù)執(zhí)行完畢。有狀態(tài)任務(wù)比無(wú)狀態(tài)任務(wù)需要考慮更多的因素,程序往往擁有更高的復(fù)雜度,因此除非必要,應(yīng)該盡量使用無(wú)狀態(tài)的 Job。
6)Listener:Quartz 擁有完善的事件和監(jiān)聽(tīng)體系,大部分組件都擁有事件,如:JobListener 監(jiān)聽(tīng)任務(wù)執(zhí)行前事件、任務(wù)執(zhí)行后事件;TriggerListener 監(jiān)聽(tīng)觸發(fā)器觸發(fā)前事件、觸發(fā)后事件;TriggerListener 監(jiān)聽(tīng)調(diào)度器開(kāi)始事件、關(guān)閉事件等等,可以注冊(cè)相應(yīng)的監(jiān)聽(tīng)器處理感興趣的事件。
2. 調(diào)度示例使用 Quartz 進(jìn)行任務(wù)調(diào)度:
package org.quartz.examples; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import java.util.ArrayList; import java.util.Date; import java.util.List; public class QuartzTest implements Job { /** * Quartz requires a public empty constructor so that the * scheduler can instantiate the class whenever it needs. */ public QuartzTest() { } /** * 該方法實(shí)現(xiàn)需要執(zhí)行的任務(wù) */ @SuppressWarnings("unchecked") @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 從 context 中獲取 instName, groupName 以及 dataMap String instName = context.getJobDetail().getKey().getName(); String groupName = context.getJobDetail().getKey().getGroup(); JobDataMap dataMap = context.getJobDetail().getJobDataMap(); // 從 dataMap 中獲取 myDescription, myValue 以及 myArray String myDescription = dataMap.getString("myDescription"); int myValue = dataMap.getInt("myValue"); ListmyArray = (List ) dataMap.get("myArray"); System.out.println("---> Instance = " + instName + ", group = " + groupName + ", description = " + myDescription + ", value =" + myValue + ", array item[0] = " + myArray.get(0)); System.out.println("Runtime: " + new Date().toString() + " <---"); } public static void main(String[] args) throws SchedulerException, InterruptedException { // 通過(guò) schedulerFactory 獲取一個(gè)調(diào)度器 SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); // 創(chuàng)建 jobDetail 實(shí)例,綁定 Job 實(shí)現(xiàn)類 // 指明 job 的名稱,所在組的名稱,以及綁定 job 類 JobDetail job = JobBuilder.newJob(QuartzTest.class).withIdentity("job1", "group1").build(); // 定義調(diào)度觸發(fā)規(guī)則 // SimpleTrigger,從當(dāng)前時(shí)間的下 1 秒開(kāi)始,每隔 1 秒執(zhí)行 1 次,重復(fù)執(zhí)行 2 次 /*Trigger trigger = TriggerBuilder.newTrigger() // 指明 trigger 的 name 和 group .withIdentity("trigger1", "group1") // 從當(dāng)前時(shí)間的下 1 秒開(kāi)始執(zhí)行,默認(rèn)為立即開(kāi)始執(zhí)行(.startNow()) .startAt(DateBuilder.evenSecondDate(new Date())) .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(1) // 每隔 1 秒執(zhí)行 1 次 .withRepeatCount(2)) // 重復(fù)執(zhí)行 2 次,一共執(zhí)行 3 次 .build();*/ // corn 表達(dá)式,先立即執(zhí)行一次,然后每隔 5 秒執(zhí)行 1 次 Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?")) .build(); // 初始化參數(shù)傳遞到 job job.getJobDataMap().put("myDescription", "Hello Quartz"); job.getJobDataMap().put("myValue", 1990); List list = new ArrayList<>(); list.add("firstItem"); job.getJobDataMap().put("myArray", list); // 把作業(yè)和觸發(fā)器注冊(cè)到任務(wù)調(diào)度中 sched.scheduleJob(job, trigger); // 啟動(dòng)計(jì)劃程序(實(shí)際上直到調(diào)度器已經(jīng)啟動(dòng)才會(huì)開(kāi)始運(yùn)行) sched.start(); // 等待 10 秒,使我們的 job 有機(jī)會(huì)執(zhí)行 Thread.sleep(10000); // 等待作業(yè)執(zhí)行完成時(shí)才關(guān)閉調(diào)度器 sched.shutdown(true); } }
運(yùn)行結(jié)果(設(shè)置了 sleep 10 秒,故在 0 秒調(diào)度一次,5 秒調(diào)度一次, 10 秒調(diào)度最后一次):
---> Instance = job1, group = group1, description = Hello Quartz, value =1990, array item[0] = firstItem Runtime: Wed Apr 19 11:24:15 CST 2017 <--- ---> Instance = job1, group = group1, description = Hello Quartz, value =1990, array item[0] = firstItem Runtime: Wed Apr 19 11:24:20 CST 2017 <--- ---> Instance = job1, group = group1, description = Hello Quartz, value =1990, array item[0] = firstItem Runtime: Wed Apr 19 11:24:25 CST 2017 <---3. cronExpression 表達(dá)式
格式:[秒] [分] [時(shí)] [每月的第幾日] [月] [每周的第幾日] [年]
字段名 | 必須的 | 允許值 | 允許的特殊字符 |
---|---|---|---|
Seconds | YES | 0-59 | , - * / |
Minutes | YES | 0-59 | , - * / |
Hours | YES | 0-23 | , - * / |
Day of month | YES | 1-31 | , - * ? / L W |
Month | YES | 1-12 or JAN-DEC | , - * / |
Day of week | YES | 1-7 or SUN-SAT | , - * ? / L # |
Year | NO | empty, 1970-2099 | , - * / |
特殊字符說(shuō)明:
字符 | 含義 |
---|---|
* | 用于 指定字段中的所有值。比如:* 在分鐘中表示 每一分鐘。 |
? | 用于 指定日期中的某一天,或是 星期中的某一個(gè)星期。 |
- | 用于 指定范圍。比如:10-12 在小時(shí)中表示 10 點(diǎn),11 點(diǎn),12 點(diǎn)。 |
, | 用于 指定額外的值。比如:MON,WED,FRI 在日期中表示 星期一, 星期三, 星期五。 |
/ | 用于 指定增量。比如:0/15 在秒中表示 0 秒, 15 秒, 30 秒, 45 秒。5/15 在秒中表示 5 秒,20 秒,35 秒,50 秒。 |
L | 在兩個(gè)字段中擁有不同的含義。比如:L 在日期(Day of month)表示 某月的最后一天。在星期(Day of week)只表示 7 或 SAT。但是,值L 在星期(Day of week)中表示 某月的最后一個(gè)星期幾。 比如:6L 表示 某月的最后一個(gè)星期五。也可以在日期(Day of month)中指定一個(gè)偏移量(從該月的最后一天開(kāi)始).比如:L-3 表示 某月的倒數(shù)第三天。 |
W | 用于指定工作日(星期一到星期五)比如:15W 在日期中表示 到 15 號(hào)的最近一個(gè)工作日。如果第十五號(hào)是周六, 那么觸發(fā)器的觸發(fā)在 第十四號(hào)星期五。如果第十五號(hào)是星期日,觸發(fā)器的觸發(fā)在 第十六號(hào)周一。如果第十五是星期二,那么它就會(huì)工作開(kāi)始在 第十五號(hào)周二。然而,如果指定 1W 并且第一號(hào)是星期六,那么觸發(fā)器的觸發(fā)在第三號(hào)周一,因?yàn)樗粫?huì) "jump" 過(guò)一個(gè)月的日子的邊界。 |
L 和 W | 可以在日期(day-of-month)合使用,表示 月份的最后一個(gè)工作日。 |
# | 用于 指定月份中的第幾天。比如:6#3 表示 月份的第三個(gè)星期五(day 6 = Friday and "#3" = the 3rd one in the month)。其它的有,2#1 表示 月份第一個(gè)星期一。4#5 表示 月份第五個(gè)星期三。注意: 如果只是指定 #5,則觸發(fā)器在月份中不會(huì)觸發(fā)。 |
注意:字符不區(qū)分大小寫(xiě),MON 和 mon 相同。
3.1 cronExpression 示例表達(dá)式 | 含義 |
---|---|
0 0 12 * * ? | 每天中午 12 點(diǎn) |
0 15 10 ? * * | 每天上午 10 點(diǎn) 15 分 |
0 15 10 * * ? | 每天上午 10 點(diǎn) 15 分 |
0 15 10 * * ? * | 每天上午 10 點(diǎn) 15 分 |
0 15 10 * * ? 2005 | 在 2005 年里的每天上午 10 點(diǎn) 15 分 |
0 * 14 * * ? | 每天下午 2 點(diǎn)到下午 2 點(diǎn) 59 分的每一分鐘 |
0 0/5 14 * * ? | 每天下午 2 點(diǎn)到 2 點(diǎn) 55 分每隔 5 分鐘 |
0 0/5 14,18 * * ? | 每天下午 2 點(diǎn)到 2 點(diǎn) 55 分, 下午 6 點(diǎn)到 6 點(diǎn) 55 分, 每隔 5 分鐘 |
0 0-5 14 * * ? | 每天下午 2 點(diǎn)到 2 點(diǎn) 5 分的每一分鐘 |
0 10,44 14 ? 3 WED | 3 月每周三的下午 2 點(diǎn) 10 分和下午 2 點(diǎn) 44 分 |
0 15 10 ? * MON-FRI | 每周一到周五的上午 10 點(diǎn) 15 分 |
0 15 10 15 * ? | 每月 15 號(hào)的上午 10 點(diǎn) 15 分 |
0 15 10 L * ? | 每月最后一天的上午 10 點(diǎn) 15 分 |
0 15 10 L-2 * ? | 每月最后兩天的上午10點(diǎn)15分 |
0 15 10 ? * 6L | 每月的最后一個(gè)星期五的上午 10 點(diǎn) 15 分 |
0 15 10 ? * 6L 2002-2005 | 2002 年到 2005 年每個(gè)月的最后一個(gè)星期五的上午 10 點(diǎn) 15 分 |
0 15 10 ? * 6#3 | 每月的第三個(gè)星期五的上午 10 點(diǎn) 15 分 |
0 0 12 1/5 * ? | 每月的 1 號(hào)開(kāi)始每隔 5 天的中午 12 點(diǎn) |
0 11 11 11 11 ? | 每年 11 月 11 號(hào)上午 11 點(diǎn) 11 分 |
監(jiān)聽(tīng)器在運(yùn)行時(shí)將其注冊(cè)到調(diào)度程序中,并且必須給出一個(gè)名稱(或者,他們必須通過(guò)他們的 getName() 來(lái)宣傳自己的名稱)。
4.1 TriggerListener 和 JobListener 示例偵聽(tīng)器與調(diào)度程序的 ListenerManager 一起注冊(cè),并且描述了監(jiān)聽(tīng)器想要接收事件的作業(yè)/觸發(fā)器的 Matcher。
1)注冊(cè)對(duì)特定作業(yè)的 JobListener:
sched.getListenerManager().addJobListener(new MyJobListener(), KeyMatcher.keyEquals(new JobKey("job1", "group1")));
2)注冊(cè)對(duì)特定組的所有作業(yè)的 JobListener:
sched.getListenerManager().addJobListener(new MyJobListener(), GroupMatcher.jobGroupEquals("group1"));
3)注冊(cè)對(duì)兩個(gè)特定組的所有作業(yè)的 JobListener:
sched.getListenerManager().addJobListener(new MyJobListener(), OrMatcher.or(GroupMatcher.jobGroupEquals("group1"), GroupMatcher.jobGroupEquals("group2")));
4)注冊(cè)一個(gè)對(duì)所有作業(yè)的 JobListener:
sched.getListenerManager().addJobListener(new MyJobListener(), EverythingMatcher.allJobs());
JobListener 實(shí)現(xiàn)類:
package org.quartz.examples; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobListener; import org.quartz.SchedulerException; public class MyJobListener implements JobListener { @Override public String getName() { return "MyJobListener"; // 一定要設(shè)置名稱 } @Override public void jobToBeExecuted(JobExecutionContext jobExecutionContext) { } @Override public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) { } @Override public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { if (jobException != null) { try { // 立即關(guān)閉調(diào)度器 context.getScheduler().shutdown(); System.out.println("Error occurs when executing jobs, shut down the scheduler."); // 給管理員發(fā)送郵件... } catch (SchedulerException e) { e.printStackTrace(); } } } }
Job 實(shí)現(xiàn)類:
package org.quartz.examples; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.quartz.impl.matchers.KeyMatcher; import java.util.ArrayList; import java.util.Date; import java.util.List; public class QuartzTest implements Job { /** * Quartz requires a public empty constructor so that the * scheduler can instantiate the class whenever it needs. */ public QuartzTest() { } /** * 該方法實(shí)現(xiàn)需要執(zhí)行的任務(wù) */ @SuppressWarnings("unchecked") @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 故意運(yùn)行異常,觀察監(jiān)聽(tīng)器是否正常工作 int i = 1/0; // 從 context 中獲取 instName, groupName 以及 dataMap String instName = context.getJobDetail().getKey().getName(); String groupName = context.getJobDetail().getKey().getGroup(); JobDataMap dataMap = context.getJobDetail().getJobDataMap(); // 從 dataMap 中獲取 myDescription, myValue 以及 myArray String myDescription = dataMap.getString("myDescription"); int myValue = dataMap.getInt("myValue"); ListmyArray = (List ) dataMap.get("myArray"); System.out.println("---> Instance = " + instName + ", group = " + groupName + ", description = " + myDescription + ", value =" + myValue + ", array item[0] = " + myArray.get(0)); System.out.println("Runtime: " + new Date().toString() + " <---"); } public static void main(String[] args) throws SchedulerException, InterruptedException { // 通過(guò) schedulerFactory 獲取一個(gè)調(diào)度器 SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); // 創(chuàng)建 jobDetail 實(shí)例,綁定 Job 實(shí)現(xiàn)類 // 指明 job 的名稱,所在組的名稱,以及綁定 job 類 JobDetail job = JobBuilder.newJob(QuartzTest.class).withIdentity("job1", "group1").build(); // 定義調(diào)度觸發(fā)規(guī)則 // SimpleTrigger,從當(dāng)前時(shí)間的下 1 秒開(kāi)始,每隔 1 秒執(zhí)行 1 次,重復(fù)執(zhí)行 2 次 /*Trigger trigger = TriggerBuilder.newTrigger() // 指明 trigger 的 name 和 group .withIdentity("trigger1", "group1") // 從當(dāng)前時(shí)間的下 1 秒開(kāi)始執(zhí)行,默認(rèn)為立即開(kāi)始執(zhí)行(.startNow()) .startAt(DateBuilder.evenSecondDate(new Date())) .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(1) // 每隔 1 秒執(zhí)行 1 次 .withRepeatCount(2)) // 重復(fù)執(zhí)行 2 次,一共執(zhí)行 3 次 .build();*/ // corn 表達(dá)式,先立即執(zhí)行 1 次,然后每隔 5 秒執(zhí)行 1 次 Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?")) .build(); // 初始化參數(shù)傳遞到 job job.getJobDataMap().put("myDescription", "Hello Quartz"); job.getJobDataMap().put("myValue", 1990); List list = new ArrayList<>(); list.add("firstItem"); job.getJobDataMap().put("myArray", list); // 注冊(cè)對(duì)特定作業(yè)的監(jiān)聽(tīng)器 sched.getListenerManager().addJobListener(new MyJobListener(), KeyMatcher.keyEquals(new JobKey("job1", "group1"))); // 把作業(yè)和觸發(fā)器注冊(cè)到任務(wù)調(diào)度中 sched.scheduleJob(job, trigger); // 啟動(dòng)計(jì)劃程序(實(shí)際上直到調(diào)度器已經(jīng)啟動(dòng)才會(huì)開(kāi)始運(yùn)行) sched.start(); // 等待 10 秒,使我們的 job 有機(jī)會(huì)執(zhí)行 Thread.sleep(10000); // 等待作業(yè)執(zhí)行完成時(shí)才關(guān)閉調(diào)度器 sched.shutdown(true); } }
運(yùn)行結(jié)果:
[ERROR] 19 四月 11:54:35.361 上午 DefaultQuartzScheduler_Worker-1 [org.quartz.core.JobRunShell] Job group1.job1 threw an unhandled Exception: java.lang.ArithmeticException: / by zero at org.quartz.examples.QuartzTest.execute(QuartzTest.java:27) at org.quartz.core.JobRunShell.run(JobRunShell.java:202) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [ERROR] 19 四月 11:54:35.361 上午 DefaultQuartzScheduler_Worker-1 [org.quartz.core.ErrorLogger] Job (group1.job1 threw an exception. org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.ArithmeticException: / by zero] at org.quartz.core.JobRunShell.run(JobRunShell.java:213) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) Caused by: java.lang.ArithmeticException: / by zero at org.quartz.examples.QuartzTest.execute(QuartzTest.java:27) at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ... 1 more Error occurs when executing jobs, shut down the scheduler.
...注冊(cè) TriggerListener 的工作原理相同。
4.2 SchedulerListener 示例SchedulerListener 在調(diào)度程序的 SchedulerListener 中注冊(cè)。SchedulerListener 幾乎可以實(shí)現(xiàn)任何實(shí)現(xiàn) org.quartz.SchedulerListener 接口的對(duì)象。
注冊(cè)對(duì)添加調(diào)度器時(shí)的 SchedulerListener:
scheduler.getListenerManager().addSchedulerListener(mySchedListener);
注冊(cè)對(duì)刪除調(diào)度器時(shí)的 SchedulerListener:
scheduler.getListenerManager().removeSchedulerListener(mySchedListener);5. 參考
Quartz Quick Start Guide
Quartz 入門詳解
幾種任務(wù)調(diào)度的 Java 實(shí)現(xiàn)方法與比較
PS:本文針對(duì)的 Quartz 版本為 Quartz 2.2.3。官方下載地址:Quartz 2.2.3 .tar.gz
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/67058.html
本文來(lái)自網(wǎng)絡(luò)一些博客的整理(包括gong1208的博客 dary1715的博客) 1、簡(jiǎn)介 這個(gè)系列介紹Spring框架實(shí)現(xiàn)定時(shí)任務(wù)的兩種方式以及一些高級(jí)的用法,包括: 1、使用Quartz,這是一個(gè)功能比較強(qiáng)大的的調(diào)度器,可以讓你的程序在指定時(shí)間執(zhí)行,也可以按照某一個(gè)頻度執(zhí)行,配置起來(lái)稍顯復(fù)雜,稍后會(huì)詳細(xì)介紹。 2、Spring3.0以后自帶的task,可以將它看成一個(gè)輕量級(jí)的Quartz,而且...
摘要:本文使用實(shí)現(xiàn)對(duì)定時(shí)任務(wù)的增刪改查啟用停用等功能。并把定時(shí)任務(wù)持久化到數(shù)據(jù)庫(kù)以及支持集群。決定什么時(shí)候來(lái)執(zhí)行任務(wù)。定義的是任務(wù)數(shù)據(jù),而真正的執(zhí)行邏輯是在中。封裝定時(shí)任務(wù)接口添加一個(gè)暫停恢復(fù)刪除修改暫停所有恢復(fù)所有 簡(jiǎn)介 Quartz是一款功能強(qiáng)大的任務(wù)調(diào)度器,可以實(shí)現(xiàn)較為復(fù)雜的調(diào)度功能,如每月一號(hào)執(zhí)行、每天凌晨執(zhí)行、每周五執(zhí)行等等,還支持分布式調(diào)度。本文使用Springboot+Myba...
摘要:在定時(shí)器接口的方法中我們可以發(fā)現(xiàn)一個(gè)方法接受接口,而也是一個(gè)接口,抽象了觸發(fā)任務(wù)執(zhí)行的觸發(fā)器。更常用的一個(gè)觸發(fā)器是,它使用表達(dá)式指定何時(shí)執(zhí)行任務(wù)。配置定時(shí)任務(wù)首先看看配置。配置提供了命名空間,讓配置定時(shí)任務(wù)非常簡(jiǎn)單。 本文參考自Spring官方文檔 34. Task Execution and Scheduling。 在程序中常常有定時(shí)任務(wù)的需求,例如每隔一周生成一次報(bào)表、每個(gè)月月末清...
閱讀 25629·2021-09-29 09:41
閱讀 4787·2021-09-10 11:20
閱讀 1918·2021-09-09 09:32
閱讀 1881·2019-08-30 15:44
閱讀 3192·2019-08-29 17:13
閱讀 2809·2019-08-29 14:14
閱讀 2062·2019-08-29 14:11
閱讀 3221·2019-08-29 12:36