springboot之定時任務


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中存儲的數據很可能是不確定的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM