Spring Boot 中實現定時任務的兩種方式!
第一種:使用注解@Scheduled
使用 @Scheduled 非常容易,直接創建一個 Spring Boot 項目,並且添加 web 依賴 spring-boot-starter-web
,項目創建成功后,添加 @EnableScheduling
注解,開啟定時任務:
首先使用 @Scheduled 注解開啟一個定時任務。
@SpringBootApplication @EnableScheduling public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
fixedRate 表示任務執行之間的時間間隔,具體是指兩次任務的開始時間間隔,即第二次任務開始時,第一次任務可能還沒結束。
@Scheduled(fixedRate=2000) public void fixedRate() { System.out.println("我是fixedRate:" + new Date()); }
fixedDelay 表示任務執行之間的時間間隔,具體是指本次任務結束到下次任務開始之間的時間間隔。
@Scheduled(fixedDelay =2000) public void fixedRate() { System.out.println("我是fixedDelay:" + new Date()); }
initialDelay 表示首次任務啟動的延遲時間。
@Scheduled(initialDelay=2000) public void fixedRate() { System.out.println("我是initialDelay:" + new Date()); }
所有時間的單位都是毫秒。
@Scheduled 注解也支持 cron 表達式,使用 cron 表達式,可以非常豐富的描述定時任務的時間。cron 表達式格式如下:
[秒] [分] [小時] [日] [月] [周] [年]
推薦使用網站生成:http://cron.qqe2.com/
這一塊需要大家注意的是,月份中的日期和星期可能會起沖突,因此在配置時這兩個得有一個是 ?
通配符含義:
-
?
表示不指定值,即不關心某個字段的取值時使用。需要注意的是,月份中的日期和星期可能會起沖突,因此在配置時這兩個得有一個是?
-
*
表示所有值,例如:在秒的字段上設置*
,表示每一秒都會觸發 -
,
用來分開多個值,例如在周字段上設置 "MON,WED,FRI" 表示周一,周三和周五觸發 -
-
表示區間,例如在秒上設置 "10-12",表示 10,11,12秒都會觸發 -
/
用於遞增觸發,如在秒上面設置"5/15" 表示從5秒開始,每增15秒觸發(5,20,35,50) -
#
序號(表示每月的第幾個周幾),例如在周字段上設置"6#3"表示在每月的第三個周六,(用 在母親節和父親節再合適不過了) -
周字段的設置,若使用英文字母是不區分大小寫的 ,即 MON 與mon相同
-
L
表示最后的意思。在日字段設置上,表示當月的最后一天(依據當前月份,如果是二月還會自動判斷是否是潤年), 在周字段上表示星期六,相當於"7"或"SAT"(注意周日算是第一天)。如果在"L"前加上數字,則表示該數據的最后一個。例如在周字段上設置"6L"這樣的格式,則表示"本月最后一個星期五" -
W
表示離指定日期的最近工作日(周一至周五),例如在日字段上設置"15W",表示離每月15號最近的那個工作日觸發。如果15號正好是周六,則找最近的周五(14號)觸發, 如果15號是周未,則找最近的下周一(16號)觸發,如果15號正好在工作日(周一至周五),則就在該天觸發。如果指定格式為 "1W",它則表示每月1號往后最近的工作日觸發。如果1號正是周六,則將在3號下周一觸發。(注,"W"前只能設置具體的數字,不允許區間"-") -
L
和W
可以一組合使用。如果在日字段上設置"LW",則表示在本月的最后一個工作日觸發(一般指發工資 )
例如,在 @Scheduled 注解中來一個簡單的 cron 表達式,每隔5秒觸發一次,如下:
@Scheduled(cron ="0/5 * * * * *") public void fixedRate() { System.out.println("我是cron:" + new Date()); }
例如:
第一種:使用第三方框架 Quartz
開發基礎:
1、定義你的job,如HollowJob,實現job接口,實現方法;
2、定義你的任務類,HollowJobScheduler
a.獲取調度器Scheduler
b.定義你的任務實例
c.定義你的觸發器
d.將任務期和觸發器綁定
e.啟動調度器
觸發器:
Quartz有一些不同的觸發器類型,不過,用得最多的是SimpleTrigger和CronTrigger。
(1)jobkey
表示job實例的標識,觸發器被觸發時,該指定的job實例會被執行。
(2)startTime
表示觸發器的時間表,第一次開始被觸發的時間,它的數據類型是java.util.Date。
(3)endTime
表示觸發器終止被觸發的時間,它的數據類型是java.util.Date。
Simple Trigger觸發器
SimpleTrigger對於設置和使用是最為簡單的一種QuartzTrigger。
它是為那種需要在特定的日期/時間啟動,且以一個可能的間隔時間重復執行n次的Job所設計的。
例如:5秒執行一次
Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//觸發器名,觸發器分組 // .startNow()//現在就啟動 .usingJobData("trigger1_data_key","trigger1_data_value")//將數據傳入觸發器的map中,這里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple觸發器”)會覆蓋JobDetail中的.usinglobDataf"message” .withSchedule( SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5)//五秒啟動一次,如果不寫那么只執行一次 )
例如:執行6次后停止
Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//觸發器名,觸發器分組 // .startNow()//現在就啟動 .usingJobData("trigger1_data_key","trigger1_data_value")//將數據傳入觸發器的map中,這里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple觸發器”)會覆蓋JobDetail中的.usinglobDataf"message” .withSchedule( SimpleScheduleBuilder.repeatSecondlyForever(5)//執行6次之后停止,默認要執行一次 )
需要注意的點
SimpleTrigger的屬性有:開始時間、結束時間、重復次數和重復的時間間隔。
重復次數屬性的值可以為0、正整數、或常量SimpleTrigger.REPEAT_INDEFINITELY。
重復的時間間隔屬性值必須大於0或長整型的正整數,以毫秒作為時間單位,當重復的時間間隔為0時,意味着與Trigger同時觸發執行。
如果有指定結束時間屬性值,則結束時間屬性優先於重復次數屬性,這樣的好處在於:當我們需要創建一個每間隔10秒鍾觸發一次直到指定的結束時間的Trigger,而無需去計算從開始到結束的所重復的次數,我們只需
使用Cron表達式:
推薦一個表達式生成網址:http://cron.qqe2.com/
Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//觸發器名,觸發器分組 // .startNow()//現在就啟動 .usingJobData("trigger1_data_key","trigger1_data_value")//將數據傳入觸發器的map中,這里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple觸發器”)會覆蓋JobDetail中的.usinglobDataf"message” .withSchedule( CronScheduleBuilder.cronSchedule("0/1 * * * * ? ")//執行6次之后停止,默認要執行一次 )
Scheduler的創建方式:
(1)StdSchdulerFactory
·使用一組參數(java.util.Properties)來創建和初始化Quarz調庭器
·配置參數一般存儲在quartz.properties文件中
·調用getScheduler方法就能創建和初始化調度器對象
生成調度器的方式:
//1.調度器 Scheduler scheduler = new StdSchedulerFactory().getDefaultScheduler(); //2.調度器 StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = stdSchedulerFactory.getScheduler();
用法一:輸出調度器開始的時間:
//4.將任務實例和觸發器綁定,他的返回值就是調度器的開始時間 Date date = scheduler.scheduleJob(jobDetail, jobTrigger);
用法二:啟動任務調度:
scheduler.start();
用法三:任務調度掛起,即暫停操作
scheduler.standby();
用法四:結束調度器
scheduler.shutdown();
shutdown(true)//表示等待所有正在執行的job執行完畢之后,在關閉Scheduler
shutdown(false)//表示直接關閉Scheduler
注意:如果任務結束了,不能通過start()來喚醒該任務,會提示錯誤
(2)DirectSchdulerFactory(了解)
DirectSchedulerFactory instance = DirectSchedulerFactory.getInstance();
Scheduler scheduler1 = instance.getScheduler();
quartz.properties屬性解析(標紅的都是項目中一般要使用的):
#設置默認調度程序的名稱,如正在使用群集功能,則必須對群集中“邏輯上”相同的調度程序的每個實例使用相同的名稱,重新賦值該值。 org.quartz.scheduler.instanceName = DefaultQuartzScheduler #如果您希望Quartz Scheduler通過RMI作為服務器導出本身,則為true。 org.quartz.scheduler.rmi.export = false #如果要連接(使用)遠程服務的調度程序,則為true。還必須指定RMI注冊表進程的主機和端口 - 通常是“localhost”端口1099 org.quartz.scheduler.rmi.proxy = false #org.quartz.scheduler.rmi.registryHost #org.quartz.scheduler.rmi.registryPort #設置這項為true使我們在調用job的execute()之前能夠開始一個UserTransaction。 org.quartz.scheduler.wrapJobExecutionInUserTransaction = false #指定的線程池(這是quartz自帶的實現類) org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool #線程數量(最好不要超過100,但是一定要 >0,創建0條線程是無意義的) org.quartz.threadPool.threadCount = 10 #優先級(最小是1,最大是10,默認是5) org.quartz.threadPool.threadPriority = 5 #自創建父線程 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true #作業最大延遲時間毫秒 org.quartz.jobStore.misfireThreshold = 60000 #數據保存方式為持久化 org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
Quartz監聽器
1.概念
Quartz的監聽髓用於當任務調度中你所關注事件發生時,能夠及時獲取這一事件的通知。類似於任務執行過程中的郵件、短信類的提醒。Quarz監聽器主要有JobListener、TriggerListener、SchedulerListener三種,顧名思義,分別表示任務、觸發器、調度器對應的監聽器。三者的使用方法類似,在開始介紹三種監聽器之前,需要明確兩個概念:全局監聽器與非全局監聽器,
二者的區別在於:
全局監聽器能夠接收到所有job/Trigger的事件通知,而非全局監聽器只能接收到在其上注冊job或Trigger的事件,不在其上注冊job或Trigger則不會進行監聽。
2.JobListener任務調度過程中,與任務Job相關的事件包括:job開始要執行的提示;job執行完成的提示燈
JobListener是一個已經存在的接口,我們可以對其重寫
其中:
1)getName方法:用於獲取該obListener的名稱。
2)jobToBeExecuted方法:Scheduler在JobDeta將要被執行時調用這個方法。
3)jobExecutionVetoed方法:Scheduler在JobDeta即將被執行,但又被TriggerListerner否決時會調用該方法
4)jobWasExecuted方法:Scheduler在jobDeta被執行之后調用這個方法
定義一個監聽器的實現MyJobListener:
//要實現默認的job監聽器接頭
public class MyJobListener implements JobListener { @Override public String getName() { System.out.println("我的名稱是:"+this.getClass().getSimpleName()); return this.getClass().getSimpleName(); } @Override public void jobToBeExecuted(JobExecutionContext jobExecutionContext) { String name = jobExecutionContext.getJobDetail().getKey().getName(); System.out.println("job的名稱是:"+name+" ;Scheduler在JobDeta將要被執行時調用這個方法。"); } @Override public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) { String name = jobExecutionContext.getJobDetail().getKey().getName(); System.out.println("job的名稱是:"+name+" ;Scheduler在JobDeta即將被執行,但又被TriggerListerner否決時會調用該方法"); } @Override public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) { String name = jobExecutionContext.getJobDetail().getKey().getName(); System.out.println("job的名稱是:"+name+" ;Scheduler在jobDeta被執行之后調用這個方法"); } }
定義你的任務
public class HollowJobSchedulerListener { public static void main(String[] args) throws SchedulerException { //1.調度器 // Scheduler scheduler = new StdSchedulerFactory().getDefaultScheduler(); StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = stdSchedulerFactory.getScheduler(); JobDetail jobDetail = JobBuilder.newJob(HollowJobListener.class) .withIdentity("job1", "job_grop1")//job名稱,分組,沒有指定組名,則默認是default .usingJobData("job1_data_key","job1_data_value")//將數據傳入任務實例的map中,這里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple觸發器”)會覆蓋JobDetail中的.usinglobDataf"message”。 .build(); //3.觸發器,由TriggerBuilder創建 Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//觸發器名,觸發器分組 // .startNow()//現在就啟動 .usingJobData("trigger1_data_key","trigger1_data_value")//將數據傳入觸發器的map中,這里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple觸發器”)會覆蓋JobDetail中的.usinglobDataf"message” .startNow() .withSchedule( SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5) ) .build(); //4.將任務實例和觸發器綁定 scheduler.scheduleJob(jobDetail, jobTrigger); //創建並注冊一個全局的監聽器( EverythingMatcher任何地方,allJobs()所有的job) //scheduler.getListenerManager().addJobListener(new MyJobListener(), EverythingMatcher.allJobs());//代表任何地方的所有job //創建一個局部的監聽器 scheduler.getListenerManager().addJobListener(new MyJobListener(), KeyMatcher.keyEquals(JobKey.jobKey("job2", "job_grop1")));//代表指定的job,通過jobkey判斷,根據指定的job名稱和job組找到指定job
//刪除監聽一樣的套路
//scheduler.getListenerManager().removeJobListenerMatcher(new MyJobListener(), KeyMatcher.keyEquals(JobKey.jobKey("job1", "job_grop1")));
//scheduler.getListenerManager().removeJobListenerMatcher(new MyJobListener(),EverythingMatcher.allJobs());
//5.啟動調度器 scheduler.start(); } }
TriggerListener監聽器(使用方法同JobListener一樣):
定義一個triggerlistener監聽器的實現類MyTirggerListener:
1)getName方法:用於獲取觸發器的名稱
2)triggerFired方法:當與監聽器相關聯的Trigger被觸發,Job上的execute)方法將被執行時,Scheduler就調用該方法。
3)vetojobExecution方法:在Trigger 觸發后,Job將要被執行時由 Scheduler 調用這個方法。TriggerListener給了一個選擇去否決Job的執行。假如這個方法返回true,這個Job將不會為此次Trigger觸發而得到執行。
4)triggerMisfired方法:Scheduler 調用這個方法是在Trigger 錯過觸發時。你應該關注此方法中持續時間長的邏輯:在出現許多錯過觸發的Trigger時,長邏輯會導致骨牌效應。你應當保持這上方法盡量的小。
5)triggerComplete方法:Trigger被觸發並且完成了Job的執行時,Scheduler調用這個方法。
public class MyTirggerListener implements TriggerListener { @Override public String getName() { String simpleName = this.getClass().getSimpleName(); System.out.println("觸發器名稱:"+simpleName); return simpleName; } @Override public void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) { String name = trigger.getKey().getName(); System.out.println("觸發器的名稱是:"+name+"被觸發"); } @Override public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) { //可以理解為將要觸發執行的job的時候,這里加了一層限制,返回true,不執行,返回false執行job String name = trigger.getKey().getName(); System.out.println("觸發器名稱:"+name+"該job沒有被觸發"); return true;//返回true,這個Job將不會為此次Trigger觸發而得到執行。
//return false;//返回false,這個JOb會執行
} @Override public void triggerMisfired(Trigger trigger) { String name = trigger.getKey().getName(); System.out.println("觸發器名稱:"+name+"沒有觸發"); } @Override public void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) { String name = trigger.getKey().getName(); System.out.println("觸發器名稱:"+name+"Trigger被觸發並且完成Job的執行了"); } }
定義你的任務:
public class HollowJobSchedulerTriggerListener { public static void main(String[] args) throws SchedulerException { //1.調度器 // Scheduler scheduler = new StdSchedulerFactory().getDefaultScheduler(); StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = stdSchedulerFactory.getScheduler(); JobDetail jobDetail = JobBuilder.newJob(HollowJobListener.class) .withIdentity("job1", "job_grop1")//job名稱,分組,沒有指定組名,則默認是default .usingJobData("job1_data_key","job1_data_value")//將數據傳入任務實例的map中,這里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple觸發器”)會覆蓋JobDetail中的.usinglobDataf"message”。 .build(); //3.觸發器,由TriggerBuilder創建 Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//觸發器名,觸發器分組 // .startNow()//現在就啟動 .usingJobData("trigger1_data_key","trigger1_data_value")//將數據傳入觸發器的map中,這里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple觸發器”)會覆蓋JobDetail中的.usinglobDataf"message” .startNow() .withSchedule( SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5) ) .build(); //4.將任務實例和觸發器綁定 scheduler.scheduleJob(jobDetail, jobTrigger); //創建並注冊一個全局的監聽器( EverythingMatcher任何地方,allTrigger()所有的監聽器) scheduler.getListenerManager().addTriggerListener(new MyTirggerListener(),EverythingMatcher.allTriggers());
//移除監聽器
//scheduler.getListenerManager().removeTriggerListenerMatcher(new MyTirggerListener(),EverythingMatcher.allTriggers());
//scheduler.getListenerManager().removeTriggerListenerMatcher(new MyTirggerListener(),KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1_data_key","trigger1_data_value")));
//創建一個局部的監聽器 //scheduler.getListenerManager().addTriggerListener(new MyTirggerListener(),KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1", "trigger_grop1")));//指定你的觸發器的名稱和分組 //5.啟動調度器 scheduler.start(); } }
trigger監聽的vetoJobExecution方法返回true時:
trigger監聽的vetoJobExecution方法返回false時:
也可以通過構造器指定觸發器的名稱:
4.SchedulerListener
SchedulerListener會在Scheduler的生命周期中關鍵事件發生時被調用。與Scheduler有關的事件包括:增加一個job/trigger,刪除一個job/trigger,scheduler發生嚴重錯誤,關閉scheduler等。
1)jobScheduled方法:用於部JobDetail時調用
2)jobunscheduled方法:用於卸載jobDetai時調用
3)triggerFinalized方法:當一個Trigger 來到了再也不會觸發的狀態時調用這個方法。除非這個Job已設置成了持久性,否則它就會從Scheduler 中移除。
4)triggerPaused(TriggerKey triggerKey)方法:Scheduler 調用這個方法是發生在一個Trigger或Trigger 組被暫停時。假如是Trigger組的話,triggerName參數將為null。
triggersPaused(String triggerGroup):觸發器組"+triggerGroup+"正在被暫停時調用
5)triggersResumed方法:Scheduler 調用這個方法是發生成一個Trigger 或Trigger組從暫停中恢復時。假如是Trigger 組的話,假如是Trigger 組的話,triggerName參數將為nul。參數將為null。
6)jobsPaused方法:當一個或一組JobDetail 暫停時調用這個方法。
7)jobsResumed方法:當一個或一組Job從暫停上恢復時調用這個方法。假如是一個Job組,jobName參數將為null。
8)schedulerError方法:在Scheduler的正常運行期間產生一個嚴重錯誤時調用這個方法。
9)schedulerStarted方法:當Schedeler 開啟時,調用該方法
10)schedulerinStandbyMode方法:當Scheduler處於StandBy模式時,調用該方法
11)schedulerShutdown方法:當Scheduler停止時,調用該方法
12)schedulingDataCleared方法:當Scheduler中的數據被清除時,調用該方法。
詳情見下:
public class MySchedulerListener implements SchedulerListener { @Override public void jobScheduled(Trigger trigger) { String name = trigger.getKey().getName(); System.out.println("觸發器名稱是:"+name+",用於部JobDetail時調用"); } @Override public void jobUnscheduled(TriggerKey triggerKey) { String name = triggerKey.getName(); System.out.println("觸發器名稱是:"+name+",用於卸載jobDetai時調用"); } @Override public void triggerFinalized(Trigger trigger) { String name = trigger.getKey().getName(); //當一個Trigger 來到了再也不會觸發的狀態時調用這個方法。除非這個Job已設置成了持久性,否則它就會從Scheduler 中移除。 System.out.println("觸發器名稱是:"+name+",觸發器被移除時時調用"); } @Override public void triggerPaused(TriggerKey triggerKey) { String name = triggerKey.getName(); //Trigger或Trigger 組被暫停時。假如是Trigger組的話,triggerName參數將為null。 System.out.println("觸發器名稱是:"+name+",Trigger或Trigger 組正在被暫停時調用"); } @Override public void triggersPaused(String triggerGroup) { System.out.println("觸發器組"+triggerGroup+"正在被暫停時調用"); } @Override public void triggerResumed(TriggerKey triggerKey) { String name = triggerKey.getName(); System.out.println("觸發器名稱是:"+name+",正在從暫停中恢復時調用"); } @Override public void triggersResumed(String triggerGroup) { System.out.println("觸發器組"+triggerGroup+"正在被恢復時調用"); } @Override public void jobAdded(JobDetail jobDetail) { System.out.println(jobDetail.getKey()+"添加工作任務!"); } @Override public void jobDeleted(JobKey jobKey) { System.out.println(jobKey+"刪除工作任務!"); } @Override public void jobPaused(JobKey jobKey) { System.out.println(jobKey+"工作任務正在被暫停!"); } @Override public void jobsPaused(String s) { System.out.println("工作組"+s+"正在被暫停!"); } @Override public void jobResumed(JobKey jobKey) { System.out.println(jobKey.getName()+"正在被恢復!"); } @Override public void jobsResumed(String s) { System.out.println("工作組"+s+"正在被恢復!"); } @Override public void schedulerError(String s, SchedulerException e) { //在Scheduler的正常運行期間產生一個嚴重錯誤時調用這個方法。 System.out.println("產生一個嚴重錯誤時調用"+s+" "+e.getUnderlyingException()); } @Override public void schedulerInStandbyMode() { //當Scheduler處於StandBy模式時,調用該方法 System.out.println("當Scheduler處於StandBy模式時,調用該方法"); } @Override public void schedulerStarted() { System.out.println("當Schedeler 開啟后,調用該方法"); } @Override public void schedulerStarting() { System.out.println("當Schedeler 開啟時,調用該方法"); } @Override public void schedulerShutdown() { System.out.println("當Scheduler停止后,調用該方法"); } @Override public void schedulerShuttingdown() { System.out.println("當Schedeler 停止時,調用該方法"); } @Override public void schedulingDataCleared() { //當Scheduler中的數據被清除時,調用該方法。 System.out.println("當Scheduler中的數據被清除時,調用該方法。"); } }
定義你的任務:
public class HollowJobSchedulerTriggerListener { public static void main(String[] args) throws SchedulerException, InterruptedException { //1.調度器 StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = stdSchedulerFactory.getScheduler(); JobDetail jobDetail = JobBuilder.newJob(HollowJobListener.class) .withIdentity("job1", "job_grop1")//job名稱,分組,沒有指定組名,則默認是default .usingJobData("job1_data_key","job1_data_value")//將數據傳入任務實例的map中,這里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple觸發器”)會覆蓋JobDetail中的.usinglobDataf"message”。 .build(); //3.觸發器,由TriggerBuilder創建 Trigger jobTrigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "trigger_grop1")//觸發器名,觸發器分組 // .startNow()//現在就啟動 .usingJobData("trigger1_data_key","trigger1_data_value")//將數據傳入觸發器的map中,這里注意:如果遇到同名的key,Trigger中的.usinglobData("message","simple觸發器”)會覆蓋JobDetail中的.usinglobDataf"message” .startNow() .withSchedule( SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(3) ) .build(); //4.將任務實例和觸發器綁定 scheduler.scheduleJob(jobDetail, jobTrigger); //創建並注冊一個全局的監聽器( EverythingMatcher任何地方,allTrigger()所有的監聽器) MySchedulerListener mySchedulerListener = new MySchedulerListener(); scheduler.getListenerManager().addSchedulerListener(mySchedulerListener); //刪除一個監聽器 // scheduler.getListenerManager().removeSchedulerListener(mySchedulerListener); //5.啟動調度器 scheduler.start(); Thread.sleep(7000L);
//停止 scheduler.standby(); Thread.sleep(7000L); //清理數據
scheduler.clear(); Thread.sleep(7000L); //關閉調度器 scheduler.shutdown(); } }
小點:
@PersistJobDataAfterExecution //多次調用Job的時候,會對]ob進行持久化,即保存一個數據的信息(不會因為每一次都創建一個新的示例導致數據記錄被清空)例如:jobdetailmap
如果你使用了@PersistJobDataAfterExecution注解,我們強烈建議你同時使用@DisallowConcurrentExecution注解,因為當同一個job(JobDetail)的兩個實例被並發執行時,由於競爭,JobDataMap中存儲的數據很可能是不確定的。