一、簡單概述
quartz就是一個任務調度框架,任務調度就是N個任務,在想要的時間執行!
它有三大核心內容:
Job:主要來是用來寫任務的具體內容Trigger:觸發器,主要是用來設定任務的時間Schedule:任務調度器,主要是用來開啟任務,并把Job和Trigger整合,統一管理
下面我先來一個快速上手的方式,讓大哥們先大致了解一下,然后在詳細聊聊三大核心內容,最后再來個監聽器收個尾就可以了!
二、快速上手
1、引入依賴
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
2、實作JOB類,撰寫需要定時的任務
public class ScheduleTask implements Job {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("執行時間:" + sdf.format(new Date()));
}
}
3、呼叫定時任務
@Component
public class ScheduleTaskService {
@PostConstruct
public void startTask(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("當前時間:" + sdf.format(new Date()));
Date startTime = new Date();
startTime.setTime(startTime.getTime() + 5000);
Date endTime = new Date();
endTime.setTime(startTime.getTime() + 10000);
try {
// 1: 定義JobDetail,并系結任務
JobDetail jobDetail = JobBuilder.newJob(ScheduleTask.class).build();
// 2: 定義Trigger觸發器,用來觸發定時任務
// 方式一:設定開始和結束時間,不設定結束時間默認一直按照呼叫周期執行
/*Trigger trigger = TriggerBuilder.newTrigger()
.startAt(startTime).endAt(endTime)
// repeatSecondlyForever(5) 周期為5s
// SimpleScheduleBuilder. 有很多方法,可以看看
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
.build();*/
// 方式二:固定執行周期
Trigger trigger = TriggerBuilder.newTrigger()
.startNow()
// withRepeatCount(3) 代表執行 3+1 次
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5).withRepeatCount(3))
.build();
// 3: 定義Schedule,并將JobDetail,Trigger系結
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
方式一的結果:

方式二的結果:

三、Job
簡要描述
主要是用來撰寫任務內容用的,寫法就是實作Job類,重寫execute()就可以了!
JobDetail
用來設定Job和一些Job的屬性
// 第一步:系結任務
JobDetail jobDetail = JobBuilder.newJob(ScheduleTask.class)
.withIdentity("testJob", "testJobGroup").build();
String group = jobDetail.getKey().getGroup();// testJob
String name = jobDetail.getKey().getName();// testJobGroup
String name1 = jobDetail.getJobClass().getName();// 創建JobDetail 類的全路徑
Job和 JobDetail 的關系?
JobDetail主要用來定義任務資料,而Job是真正的業務邏輯,如果直接使用Job,當是并發場景的話,可能會存在多個Job同時執行,可能會出現問題,如果是JobDetail,則每次執行定時任務的時候,都是創建一個新的Job并不會產生并發問題!
JobDataMap
相當于一個Map集合,用來存盤資料的,可以在創建JobDetail的時候可以傳遞引數,當實作Job的時候可以獲取引數!
來把,寶貝,瞅瞅代碼:
JobDetail jobDetail = JobBuilder.newJob(ScheduleTask.class)
.usingJobData("testJobDataMap", "testJobDataMapValue")build();
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDetail jobDetail = jobExecutionContext.getJobDetail();
JobDataMap jobDataMap = jobDetail.getJobDataMap();
String[] keys = jobDataMap.getKeys();
System.out.println(jobDataMap.get(keys[0]));
System.out.println("執行時間:" + sdf.format(new Date()) + ",執行內容:你真棒!你太棒了,你真是太棒了!");
}
注意:JobDataMap不是只能在創建JobDetail的時候可以用,創建Trigger的時候也可以用!
再來瞅瞅代碼,兄弟!
SimpleTrigger trigger = TriggerBuilder.newTrigger()
.usingJobData("triggerJobDataKey","triggerJobDataValue")
.startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(10)).build();
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Trigger trigger = jobExecutionContext.getTrigger();
JobDataMap triggerJobDataMap = trigger.getJobDataMap();
String[] keys1 = triggerJobDataMap.getKeys();
System.out.println(triggerJobDataMap.get(keys1[0]));
System.out.println("執行時間:" + sdf.format(new Date()) + ",執行內容:你真棒!你太棒了,你真是太棒了!");
}
JobExecutionContext
execute()方法的引數,可以通過它來傳遞一些資訊!比如JobDetai,Trigger等等
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDetail jobDetail = jobExecutionContext.getJobDetail();
JobDataMap jobDataMap = jobDetail.getJobDataMap();
String[] keys = jobDataMap.getKeys();
System.out.println(jobDataMap.get(keys[0]));
Trigger trigger = jobExecutionContext.getTrigger();
JobDataMap triggerJobDataMap = trigger.getJobDataMap();
String[] keys1 = triggerJobDataMap.getKeys();
System.out.println(triggerJobDataMap.get(keys1[0]));
System.out.println("執行時間:" + sdf.format(new Date()) + ",執行內容:你真棒!你太棒了,你真是太棒了!");
}
Job 的狀態
Job有兩種狀態,分別是有狀態和無狀態;
- 無狀態Job:每次定時執行的時候,JobDataMap是獨立的,資訊不共享,默認是無狀態的!
- 有狀態Job:每次定時執行的時候,JobDataMap是獨立的,資訊是共享的,可以做程式計數,在實作Job類的上面添加
@PersistJobDataAfterExecution即可,建議搭配@DisallowConcurrentExecution食用,因為如果開啟狀態的話可能會引起并發問題,這個注解會禁止并發執行相同的JobDetail實體!
簡單實作“記錄任務的執行次數”!
@Service
public class ScheduleService02 {
@PostConstruct
public void startTask(){
try {
JobDetail jobDetail = JobBuilder.newJob(ScheduleTask02.class)
.usingJobData("count", 0)
.withIdentity("jobName", "jobGroup")
.build();
SimpleTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("triggerName", "triggerGroup")
.startNow()
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(10))
.build();
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class ScheduleTask02 implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDetail jobDetail = jobExecutionContext.getJobDetail();
JobDataMap jobDataMap = jobDetail.getJobDataMap();
Integer count = (Integer) jobDataMap.get("count");
System.out.println("count::" + ++count);
jobDataMap.put("count", count);
}
}
四、Trigger
簡要描述
主要是用來設定任務執行時間,比如任務開始時間,結束時間,執行周期,執行次數,某天的某一時刻等等,都可以時間,極其靈活!
SimpleTrigger
SimpleTrigger trigger = TriggerBuilder.newTrigger()
// 設定執行周期,單位秒,并設定執行次數
// 專案啟動就執行,每5s一次,一共執行4次(3 + 1)
.startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5).withRepeatCount(3))
.build();
Date startTime = new Date();
startTime.setTime(startTime.getTime() + 5000);
Date endTime = new Date();
endTime.setTime(startTime.getTime() + 10000);
// 2、通過Trigger設定定時引數
SimpleTrigger trigger = TriggerBuilder.newTrigger()
// 設定開始時間和結束時間
.startAt(startTime).endAt(endTime)
// 每5秒執行一次
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
.build();
CronTrigger
Trigger trigger = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();
"0/5 * * * * ?"是cron運算式它是由秒 分 時 日 月 星期組成的,推薦一個在線生成cron運算式的網站!用這個網站就行,很簡單!
五、Schedule
簡要描述
其實就是任務調度管理器,把Job和Trigger整合,并開始任務!
常用方法
整合:scheduler.scheduleJob(jobDetail, trigger);
開始:scheduler.start();
暫停:scheduler.standby();
立馬關閉:scheduler.shutdown(false);
等正在執行的任務結束后關閉:scheduler.shutdown(true);
六、監聽器
簡要描述
監聽器主要是想在任務某一時刻做一些操作!比如任務執行前,或者執行后!有三類監聽器,分別是JobListener,TriggerListener,ScheduleListener三種.
如果用代碼實作那?
1、撰寫任務內容
2、撰寫監聽器(顯現JobListener,TriggerListener,ScheduleListener就行,重寫方法即可!)
3、正常定義三大核心內容后,添加監聽器即可
友情提醒:方法描述在代碼后面,其實只需要簡單看看代碼,只需要怎么寫就行,然后看看方法描述就可以了!
1、撰寫任務內容
/**
* @author: tianjx
* @date: 2022/1/26 9:43
* @description: 撰寫任務內容
*/
public class ScheduleTask06 implements Job {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("執行時間:" + sdf.format(new Date()) + ",執行內容:你真棒,你太棒了,你真的太棒了!");
}
}
2、撰寫監聽器(顯現JobListener,TriggerListener,ScheduleListener就行,重寫方法即可!)
/**
* @author: tianjx
* @date: 2022/1/26 9:53
* @description: JobListener監聽器
*/
public class MyJobListener implements JobListener {
@Override
public String getName() {
String name = getClass().getName();
System.out.println("監聽器的名稱:" + name);
return name;
}
@Override
public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
String name = jobExecutionContext.getJobDetail().getKey().getName();
System.out.println("Job的名稱:" + name + ",【jobToBeExecuted()】方法是Schedule在JobDetail執行前呼叫!");
}
@Override
public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
String name = jobExecutionContext.getJobDetail().getKey().getName();
System.out.println("Job的名稱:" + name + ",【jobExecutionVetoed()】方法是Schedule在JobDetail即將執行,但是被TriggerListener拒絕之后呼叫");
}
@Override
public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
String name = jobExecutionContext.getJobDetail().getKey().getName();
System.out.println("Job的名稱:" + name + ",【jobWasExecuted()】方法是Schedule在JobDetail執行之后呼叫!");
}
}
------------------------------
/**
* @author: tianjx
* @date: 2022/1/26 10:09
* @description: TriggerListener監聽器
*/
public class MyTriggerListener implements TriggerListener {
private String name;
public MyTriggerListener(String name){
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) {
String name = trigger.getKey().getName();
System.out.println(name + "【triggerFired()】被觸發!");
}
@Override
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {
String name = trigger.getKey().getName();
System.out.println(name + "【vetoJobExecution()】用來控制任務是否執行!");
return false;// true:表示不會執行Job方法
}
@Override
public void triggerMisfired(Trigger trigger) {
String name = trigger.getKey().getName();
System.out.println(name + "【triggerMisfired()】錯過觸發!");
}
@Override
public void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) {
String name = trigger.getKey().getName();
System.out.println(name + "【triggerComplete()】完成觸發!");
}
}
---------
/**
* @author: tianjx
* @date: 2022/1/26 10:34
* @description: SchedulerListener監聽器
*/
public class MyScheduleListener implements SchedulerListener {
@Override
public void jobScheduled(Trigger trigger) {
String name = trigger.getJobKey().getName();
System.out.println(name + "完成部署!");
}
@Override
public void jobUnscheduled(TriggerKey triggerKey) {
System.out.println(triggerKey + "完成卸載!");
}
@Override
public void triggerFinalized(Trigger trigger) {
System.out.println("觸發器被移除" + trigger.getJobKey().getName());
}
@Override
public void triggerPaused(TriggerKey triggerKey) {
System.out.println(triggerKey + "正在被暫停!");
}
@Override
public void triggersPaused(String s) {
System.out.println(s + "正在被暫停");
}
@Override
public void triggerResumed(TriggerKey triggerKey) {
System.out.println(triggerKey + "正在從暫停中恢復!");
}
@Override
public void triggersResumed(String s) {
System.out.println(s + "正在從暫停中恢復!");
}
@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 + "正在從暫停中恢復!");
}
@Override
public void jobsResumed(String s) {
System.out.println(s + "正在從暫停中恢復");
}
@Override
public void schedulerError(String s, SchedulerException e) {
System.out.println("產生嚴重錯誤時呼叫: " + s + " " + e.getUnderlyingException());
}
@Override
public void schedulerInStandbyMode() {
System.out.println("調度器在掛起模式下呼叫");
}
@Override
public void schedulerStarted() {
System.out.println("調度器 開啟時呼叫");
}
@Override
public void schedulerStarting() {
System.out.println("調度器 正在開啟時呼叫");
}
@Override
public void schedulerShutdown() {
System.out.println("調度器 已經被關閉 時呼叫");
}
@Override
public void schedulerShuttingdown() {
System.out.println("調度器 正在被關閉 時呼叫");
}
@Override
public void schedulingDataCleared() {
System.out.println("調度器的資料被清除時呼叫");
}
}
3、正常定義三大核心內容后,添加監聽器即可
/**
* @author: tianjx
* @date: 2022/1/26 9:46
* @description: 添加監聽器
*/
@Component
public class ScheduleListenerService {
@PostConstruct
public void startTask(){
Date endTime = new Date();
endTime.setTime(endTime.getTime() + 10000);
try {
// 1、獲取JobDetail,并系結Job
JobDetail jobDetail = JobBuilder.newJob(ScheduleTask06.class).withIdentity("jobName","jobGroup").build();
// 2、獲取Trigger,并設定定時任務
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("triggerName", "triggerGroup").startNow().endAt(endTime).withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();
// 3、通過Schedule,系結JobDetail和Trigger,并開始任務
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 添加監聽器
// scheduler.getListenerManager().addJobListener(new MyJobListener(), EverythingMatcher.allJobs());
// scheduler.getListenerManager().addTriggerListener(new MyTriggerListener("myTrigger"), EverythingMatcher.allTriggers());
scheduler.getListenerManager().addSchedulerListener(new MyScheduleListener());
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
JobListener方法描述
getName():用于獲取改JobListener 的名稱jobToBeExecuted():Scheduler 在 JobDetail 將要被執行時呼叫這個方法jobExecutionVetoed():Scheduler 在 JobDetail 即將被執行,但又被 TriggerListener 否決時會呼叫該方法jobWasExecuted():Scheduler 在 JobDetail 被執行之后呼叫這個方法
TriggerListener方法描述
getName():用于獲取觸發器的名稱triggerFired():當與監聽器相關聯的Trigger被觸發,Job上的execute()方法將被執行時,Scheduler就呼叫該方法vetoJobExecution():在 Trigger 觸發后,Job 將要被執行時由 Scheduler 呼叫這個方法,TriggerListener 給了一個選擇去否決 Job 的執行,假如這個方法回傳 true,這個 Job 將不會為此次 Trigger 觸發而得到執行triggerMisfired():Scheduler 呼叫這個方法是在 Trigger 錯過觸發時,你應該關注此方法中持續時間長的邏輯:在出現許多錯過觸發的 Trigger 時,長邏輯會導致骨牌效應,所以應當保持這方法盡量的小triggerComplete():Trigger 被觸發并且完成了 Job 的執行時,Scheduler 呼叫這個方法,
ScheduleListener方法描述
jobScheduled():用于部署JobDetail時呼叫jobUnscheduled():用于卸載JobDetail時呼叫triggerFinalized():當一個 Trigger 來到了再也不會觸發的狀態時呼叫這個方法,除非這個 Job 已設定成了持久性,否則它就會從 Scheduler 中移除,triggersPaused():Scheduler 呼叫這個方法是發生在一個 Trigger 或 Trigger 組被暫停時,假如是 Trigger 組的話,triggerName 引數將為 null,triggersResumed():Scheduler 呼叫這個方法是發生成一個 Trigger 或 Trigger 組從暫停中恢復時,假如是 Trigger 組的話,假如是 Trigger 組的話,triggerName 引數將為 null,引數將為 null,jobsPaused():當一個或一組 JobDetail 暫停時呼叫這個方法,jobsResumed():當一個或一組 Job 從暫停上恢復時呼叫這個方法,假如是一個 Job 組,jobName 引數將為 null,schedulerError():在 Scheduler 的正常運行期間產生一個嚴重錯誤時呼叫這個方法,schedulerStarted():當Scheduler 開啟時,呼叫該方法schedulerInStandbyMode(): 當Scheduler處于StandBy模式時,呼叫該方法schedulerShutdown():當Scheduler停止時,呼叫該方法schedulingDataCleared():當Scheduler中的資料被清除時,呼叫該方法,
第一次寫這么多的內容,花費了不少的時間,差點放棄,哈哈哈哈!如果感覺寫的邏輯不清楚或有問題的地方希望大家能夠指出來!
感謝大家的閱讀,我是Alson_Code🆒,一個喜歡把簡單問題復雜化,把復雜問題簡單化的程式猿! ?
參考文章:菜農日
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/421869.html
標籤:其他
