springboot內建quartz
一,quartz基本概念
1.Job
Job,JobDetail,JobBuilder,JobExecutionContext
Job?
job英文單詞的意思就是工作,意味着你需要排程器具體要做的事情,job是一個工作任務排程的接口,具體要被排程的任務要實作該接口,重寫該接口定義的execute方法(具體任務)編寫任務的業務邏輯。
job執行個體在Quartz中的生命周期:每次排程器執行job時,他在調用execute方法前都會建立一個job執行個體,調用方法完成後,關聯的job執行個體被釋放,然後垃圾回收。(即每次job的構造方法都會被執行)
jobDetail?
通過傳入job類型,JobBuilder會産生jobDetail執行個體,jobDetail存儲着該類型的job的一些執行個體資訊,排程器需要借助jobDetail來添加job執行個體
重要資訊:
- name:任務名稱
- group:任務組名稱(會有預設組名)
- jobDataMap
JobExecutionContext?
排程器在調用一個job的execute方法時,會将JobExecutionContext傳遞給該方法,job通過該JobExecutionContext對象可以通路到Quartz運作時候得環境和job本身的明細資料(job帶有的資訊)
JobBuilder?
jobDetail生成器
補充
- @DisallowConcurrentExecution:相同的jobDetail不能并發執行,不同的jobDetail可以并發執行,
- @PersistJobDataAfterExecution:将該注解加在job類上,告訴Quartz在成功執行了job類的execute方法後(沒有發生任何異常),更新JobDetail中JobDataMap的資料,使得該job(即JobDetail)在下一次執行的時候,JobDataMap中是更新後的資料,而不是更新前的舊資料
示例:
//由job類生産jobDetail
JobDetail jobDetail = newJob(TestJob.class) //産生Job執行個體,job資訊存儲在jobDetail中
.usingJobData("key1","val1")//通過jobDataMap為job執行個體增加屬性,然後再傳遞到排程器中去
.usingJobData("key2","val2")
.withIdentity("helloTask","task1")
.build();//由jobBuilder生成jobDetail
2.Trigger
觸發器
相關屬性
- jobKey屬性:當trigger觸發時被執行的job的身份;
- startTime屬性:設定trigger第一次觸發的時間;該屬性的值是java.util.Date類型,表示某個指定的時間點
- endTime屬性:表示trigger失效的時間點。
- 優先級(priority)如果你的trigger很多(或者Quartz線程池的工作線程太少),Quartz可能沒有足夠的資源同時觸發所有的trigger;這種情況下,你可能希望控制哪些trigger優先使用Quartz的工作線程,要達到該目的,可以在trigger上設定priority屬性。比如,你有N個trigger需要同時觸發,但隻有Z個工作線程,優先級最高的Z個trigger會被首先觸發。如果沒有為trigger設定優先級,trigger使用預設優先級,值為5;priority屬性的值可以是任意整數,正數、負數都可以。注意:隻有同時觸發的trigger之間才會比較優先級。10:59觸發的trigger總是在11:00觸發的trigger之前執行。如果trigger是可恢複的,在恢複後再排程時,優先級與原trigger是一樣的。
常用的觸發器
SimpleTrigger
SimpleTrigger可以滿足的排程需求是:在具體的時間點執行一次,或者在具體的時間點執行,并且以指定的間隔重複執行若幹次。
示例:
//SimpleTrigger
SimpleTrigger simpleTrigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger1","group1")//觸發器辨別
.startAt(startTime)//開始觸發時間
.forJob("helloTask","task1")//綁定的任務組
.withSchedule(simpleSchedule()//排程設定
.withRepeatCount(10)//重複次數
.withIntervalInMilliseconds(10))//執行頻率
.endAt(endTime)//結束時間
.build();
CronTrigger
CronTrigger通常比Simple Trigger更有用,如果您需要基于月曆的概念而不是按照SimpleTrigger的精确指定間隔進行重新啟動的作業啟動計劃。使用CronTrigger,您可以指定号時間表,例如“每周五中午”或“每個工作日和上午9:30”,甚至“每周一至周五上午9:00至10點之間每5分鐘”和1月份的星期五“。
即使如此,和SimpleTrigger一樣,CronTrigger有一個startTime,它指定何時生效,以及一個(可選的)endTime,用于指定何時停止計劃。
CronTrigger重點就是cron表達式,類似于spring自帶的定時器中的cron表達式
可以參考這個:spring自帶定時器
示例:
//CronTrigger
CronTrigger cronTrigger = (CronTrigger) newTrigger()
.withIdentity("trigger2","group2")//觸發器辨別
.startAt(startTime)//開始觸發時間
.forJob("helloTask1","task2")//綁定的任務組
.withSchedule(cronSchedule("0 42 10 * * ?")//cron表達式 --- 每天10點42分執行
.withMisfireHandlingInstructionFireAndProceed())//錯過觸發 -- 一般是智能模式
.endAt(endTime)//結束時間
.build();
3.Scheduler
配置好任務器和觸發器就可以開始排程了
排程器工廠(SchedulerFactory)
所有的排程器示例都需要經過SchedulerFactory建立,而SchedulerFactory是根據quartz.properties檔案定義的屬性來建立和初始化Quartz Scheduler
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
示例:
//擷取排程工廠
SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
//從工廠中擷取排程器
Scheduler sched = schedFact.getScheduler();
//開始排程
sched.start();
//挂起
//sched.standby();
//關閉任務排程
//1.等待目前任務執行完畢在關閉任務排程
//sched.shutdown(true);
//2.直接關閉任務排程
//sched.shutdown(false);
//傳入排程任務和任務觸發器
sched.scheduleJob(jobDetail,simpleTrigger);
監聽器
1.任務監聽器
/**
* @Description: 任務監聽器
* @Author: Kevin
* @CreateDate: 2019/5/8 2:37
* @UpdateUser: Kevin
* @UpdateDate: 2019/5/8 2:37
* @UpdateRemark: 修改内容
* @Version: 1.0
*/
public class TestJobListener implements JobListener {
/**
* 擷取監聽器名
* @return
*/
@Override
public String getName() {
return null;
}
/**
* 執行任務前調用
* @param jobExecutionContext
*/
@Override
public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
}
/**
* 執行任務前,但是該任務被拒絕執行時調用
* @param jobExecutionContext
*/
@Override
public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
}
/**
* 執行任務後調用
* @param jobExecutionContext
* @param e
*/
@Override
public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
}
}
//全局任務監聽配置
sched.getListenerManager().addJobListener(new TestJobListener(), EverythingMatcher.allJobs());
//局部任務監聽配置
sched.getListenerManager().addJobListener(new TestJobListener(), KeyMatcher.keyEquals(new JobKey("helloTask","task1")));
完整代碼:
public static void test(Date startTime,Date endTime) throws SchedulerException {
//由job類生産jobDetail
JobDetail jobDetail = newJob(TestJob.class) //産生Job執行個體,job資訊存儲在jobDetail中
.usingJobData("key1","val1")//通過jobDataMap為job執行個體增加屬性,然後再傳遞到排程器中去
.usingJobData("key2","val2")
.withIdentity("helloTask","task1")
.build();//由jobBuilder生成jobDetail
//SimpleTrigger
SimpleTrigger simpleTrigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger1","group1")//觸發器辨別
.startAt(startTime)//開始觸發時間
.forJob("helloTask","task1")//綁定的任務組
.withSchedule(simpleSchedule()//排程設定
.withRepeatCount(10)//重複次數
.withIntervalInMilliseconds(10))//執行頻率
.endAt(endTime)//結束時間
.build();
//CronTrigger
CronTrigger cronTrigger = (CronTrigger) newTrigger()
.withIdentity("trigger2","group2")//觸發器辨別
.startAt(startTime)//開始觸發時間
.forJob("helloTask1","task2")//綁定的任務組
.withSchedule(cronSchedule("0 42 10 * * ?")//cron表達式 --- 每天10點42分執行
.withMisfireHandlingInstructionFireAndProceed())//錯過觸發 -- 一般是智能模式
.endAt(endTime)//結束時間
.build();
//擷取排程工廠
SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
//從工廠中擷取排程器
Scheduler sched = schedFact.getScheduler();
//開始排程
sched.start();
//挂起
//sched.standby();
//關閉任務排程
//1.等待目前任務執行完畢在關閉任務排程
//sched.shutdown(true);
//2.直接關閉任務排程
//sched.shutdown(false);
//傳入排程任務和任務觸發器
sched.scheduleJob(jobDetail,simpleTrigger);
//全局任務監聽配置
sched.getListenerManager().addJobListener(new TestJobListener(), EverythingMatcher.allJobs());
//局部任務監聽配置
sched.getListenerManager().addJobListener(new TestJobListener(), KeyMatcher.keyEquals(new JobKey("helloTask","task1")));
}