SpringBoot整合Quartz實現定時任務的動態建立、啟動、暫停、恢復、刪除。
點選上方 "程式設計師小樂"關注, 星標或置頂一起成長
後臺回覆“大禮包”有驚喜禮包!
關注訂閱號「程式設計師小樂」,收看更多精彩內容
每日英文
When you are free from desire, you will be happy, because you will never be disappointed.
當你沒有慾望,你就會快樂,因為你永不會失望。
每日掏心話
懂得進退,才能成就人生;懂得取捨,才能淡定從容;懂得知足,才能怡養心性;懂得刪減,才能輕鬆釋然;懂得變通,才會少走彎路;懂得反思,才會提高自己。
來自:毅大師 | 責編:樂樂
連結:blog.csdn.net/qq_39648029/article/details/108993476
後端架構師(ID:study_tech)第 1068 次推文
往日回顧:京東單方面辭退38歲 P7 員工,勞動仲裁京東三次敗訴,員工復崗三天又收解聘通知
正文
看了好多文章,都只講了基礎的demo用法,也就是簡單的建立執行定時任務,對定時任務的管理卻很少。
我這裡從0開始搭建一個簡單的demo,包括定時任務的各種操作,以及API的一些用法,可以實現大多場景的需求。如:
-
普通定時任務的建立、啟動、停止。
-
動態建立定時任務,如建立一個訂單,5分鐘後執行某某操作。
一、整個 Quartz 的程式碼流程基本基本如下:
-
首先需要建立我們的任務(Job),比如取消訂單、定時傳送簡訊郵件之類的,這是我們的任務主體,也是寫業務邏輯的地方。
-
建立任務排程器(Scheduler),這是用來排程任務的,主要用於啟動、停止、暫停、恢復等操作,也就是那幾個api的用法。
-
建立任務明細(JobDetail),最開始我們編寫好任務(Job)後,只是寫好業務程式碼,並沒有觸發,這裡需要用JobDetail來和之前建立的任務(Job)關聯起來,便於執行。
-
建立觸發器(Trigger),觸發器是來定義任務的規則的,比如幾點執行,幾點結束,幾分鐘執行一次等等。這裡觸發器主要有兩大類(SimpleTrigger和CronTrigger)。
-
根據Scheduler來啟動JobDetail與Trigger
二、進入正題,引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
三、建立Job
需實現Job介面,這個介面就一個execute()方法需要重寫,方法內容就是具體的業務邏輯。如果是動態任務呢,比如取消訂單,每次執行都是不同的訂單號。
這個時候就需要在建立任務(JobDetail)或者建立觸發器(Trigger)的那裡傳入引數,然後在這裡通過JobExecutionContext來獲取引數進行處理,
在公眾號程式設計師小樂後臺回覆“offer”,獲取演算法面試題和答案。
import com.dy.utils.DateUtil;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
/**
* @program: xiudo-ota
* @description: 測試定時任務
* @author: zhang yi
* @create: 2020-10-09 14:38
*/
@DisallowConcurrentExecution//Job中的任務有可能併發執行,例如任務的執行時間過長,而每次觸發的時間間隔太短,則會導致任務會被併發執行。如果是併發執行,就需要一個數據庫鎖去避免一個數據被多次處理。
public class TestJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.err.println(jobExecutionContext.getJobDetail().getJobDataMap().get("name"));
System.err.println(jobExecutionContext.getJobDetail().getJobDataMap().get("age"));
System.err.println(jobExecutionContext.getTrigger().getJobDataMap().get("orderNo"));
System.err.println("定時任務執行,當前時間:"+ DateUtil.formatDateTime(new Date()));
}
}
四、建立任務排程器(Scheduler)
這裡採用Spring IOC,所以直接注入完事。如果是普通的,則需通過工廠建立。
工廠:
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
IOC:
@Autowired
private Scheduler scheduler;
五、建立任務明細(JobDetail)
/**通過JobBuilder.newJob()方法獲取到當前Job的具體實現(以下均為鏈式呼叫)
* 這裡是固定Job建立,所以程式碼寫死XXX.class
* 如果是動態的,根據不同的類來建立Job,則 ((Job)Class.forName("com.zy.job.TestJob").newInstance()).getClass()
* 即是 JobBuilder.newJob(((Job)Class.forName("com.zy.job.TestJob").newInstance()).getClass())
* */
JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
/**給當前JobDetail新增引數,K V形式*/
.usingJobData("name","zy")
/**給當前JobDetail新增引數,K V形式,鏈式呼叫,可以傳入多個引數,在Job實現類中,可以通過jobExecutionContext.getJobDetail().getJobDataMap().get("age")獲取值*/
.usingJobData("age",23)
/**新增認證資訊,有3種重寫的方法,我這裡是其中一種,可以檢視原始碼看其餘2種*/
.withIdentity("我是name","我是group")
.build();//執行
六、建立觸發器(Trigger)
這裡主要分為兩大類SimpleTrigger、CronTrigger。
SimpleTrigger:是根據它自帶的api方法設定規則,比如每隔5秒執行一次、每隔1小時執行一次。
Trigger trigger = TriggerBuilder.newTrigger()
/**給當前JobDetail新增引數,K V形式,鏈式呼叫,可以傳入多個引數,在Job實現類中,可以通過jobExecutionContext.getTrigger().getJobDataMap().get("orderNo")獲取值*/
.usingJobData("orderNo", "123456")
/**新增認證資訊,有3種重寫的方法,我這裡是其中一種,可以檢視原始碼看其餘2種*/
.withIdentity("我是name","我是group")
/**立即生效*/
// .startNow()
/**開始執行時間*/
.startAt(start)
/**結束執行時間,不寫永久執行*/
.endAt(start)
/**新增執行規則,SimpleTrigger、CronTrigger的區別主要就在這裡*/
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
/**每隔3s執行一次,api方法有好多規則自行檢視*/
.withIntervalInSeconds(3)
/**一直執行,如果不寫,定時任務就執行一次*/
.repeatForever()
)
.build();//執行
CronTrigger:這就比較常用了,是基於Cron表示式來實現的。
CronTrigger trigger = TriggerBuilder.newTrigger()
/**給當前JobDetail新增引數,K V形式,鏈式呼叫,可以傳入多個引數,在Job實現類中,可以通過jobExecutionContext.getTrigger().getJobDataMap().get("orderNo")獲取值*/
.usingJobData("orderNo", "123456")
/**新增認證資訊,有3種重寫的方法,我這裡是其中一種,可以檢視原始碼看其餘2種*/
.withIdentity("我是name","我是group")
/**立即生效*/
// .startNow()
/**開始執行時間*/
.startAt(start)
/**結束執行時間,不寫永久執行*/
.endAt(start)
/**新增執行規則,SimpleTrigger、CronTrigger的區別主要就在這裡,我這裡是demo,寫了個每2分鐘執行一次*/
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 * * * ?"))
.build();//執行
注意:.startNow( )和.startAt( )這裡有個坑,這兩個方法是對同一個成員變數進行修改的 也就是說startAt和startNow同時呼叫的時候任務開始的時間是按後面呼叫的方法為主的,誰寫在後面用誰。
七、啟動任務
/**新增定時任務*/
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
/**啟動*/
scheduler.start();
}
以上,任務的建立啟動都完事了,後面就是任務的暫停、恢復、刪除。比較簡單,大致原理就是我們在建立任務明細(JobDetail)和建立觸發器(Trigger)時,會呼叫.withIdentity(key,group)來傳入認證資訊,後續就是根據這些認證資訊來管理任務(通過api方法)
八、任務的暫停
scheduler.pauseTrigger(TriggerKey.triggerKey("我是剛才寫的name","我是剛才寫的group"));
九、任務的恢復
scheduler.resumeTrigger(TriggerKey.triggerKey("我是剛才寫的name","我是剛才寫的group"));
根據你寫的方式來獲取。
在公眾號程式設計師小樂後臺回覆“Java”,獲取Java面試題和答案。
十、任務的刪除
scheduler.pauseTrigger(TriggerKey.triggerKey("我是剛才寫的name","我是剛才寫的group"));//暫停觸發器
scheduler.unscheduleJob(TriggerKey.triggerKey("我是剛才寫的name","我是剛才寫的group"));//移除觸發器
scheduler.deleteJob(JobKey.jobKey("我是剛才寫的name","我是剛才寫的group"));//刪除Job
最後附上基本程式碼,Job實現在上面:
@Autowired
private Scheduler scheduler;
@PostMapping("/Quartz")
@ApiOperation(value = "定時任務_建立", notes = "建立")
@ResponseBody
public Object quartz(@RequestParam("orderNo") String orderNo) throws Exception {
Date start=new Date(System.currentTimeMillis() + 7 * 1000);//當前時間7秒之後
/**通過JobBuilder.newJob()方法獲取到當前Job的具體實現(以下均為鏈式呼叫)
* 這裡是固定Job建立,所以程式碼寫死XXX.class
* 如果是動態的,根據不同的類來建立Job,則 ((Job)Class.forName("com.zy.job.TestJob").newInstance()).getClass()
* 即是 JobBuilder.newJob(((Job)Class.forName("com.zy.job.TestJob").newInstance()).getClass())
* */
JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
/**給當前JobDetail新增引數,K V形式*/
.usingJobData("name","zy")
/**給當前JobDetail新增引數,K V形式,鏈式呼叫,可以傳入多個引數,在Job實現類中,可以通過jobExecutionContext.getJobDetail().getJobDataMap().get("age")獲取值*/
.usingJobData("age",23)
/**新增認證資訊,有3種重寫的方法,我這裡是其中一種,可以檢視原始碼看其餘2種*/
.withIdentity(orderNo)
.build();//執行
Trigger trigger = TriggerBuilder.newTrigger()
/**給當前JobDetail新增引數,K V形式,鏈式呼叫,可以傳入多個引數,在Job實現類中,可以通過jobExecutionContext.getTrigger().getJobDataMap().get("orderNo")獲取值*/
.usingJobData("orderNo", orderNo)
/**新增認證資訊,有3種重寫的方法,我這裡是其中一種,可以檢視原始碼看其餘2種*/
.withIdentity(orderNo)
/**立即生效*/
// .startNow()
/**開始執行時間*/
.startAt(start)
/**結束執行時間*/
// .endAt(start)
/**新增執行規則,SimpleTrigger、CronTrigger的區別主要就在這裡*/
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
/**每隔1s執行一次*/
.withIntervalInSeconds(3)
/**一直執行,*/
.repeatForever()
)
.build();//執行
//CronTrigger trigger = TriggerBuilder.newTrigger()
// /**給當前JobDetail新增引數,K V形式,鏈式呼叫,可以傳入多個引數,在Job實現類中,可以通過jobExecutionContext.getTrigger().getJobDataMap().get("orderNo")獲取值*/
// .usingJobData("orderNo", orderNo)
// /**新增認證資訊,有3種重寫的方法,我這裡是其中一種,可以檢視原始碼看其餘2種*/
// .withIdentity(orderNo)
// /**開始執行時間*/
// .startAt(start)
// /**結束執行時間*/
// .endAt(start)
// /**新增執行規則,SimpleTrigger、CronTrigger的區別主要就在這裡*/
// .withSchedule(CronScheduleBuilder.cronSchedule("* 30 10 ? * 1/5 2018"))
// .build();//執行
/**新增定時任務*/
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
/**啟動*/
scheduler.start();
}
System.err.println("--------定時任務啟動成功 "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" ------------");
return "ok";
}
@PostMapping("/shutdown")
@ApiOperation(value = "定時任務_停止", notes = "停止")
@ResponseBody
public Object shutdown(@RequestParam("orderNo") String orderNo) throws IOException, SchedulerException {
scheduler.pauseTrigger(TriggerKey.triggerKey(orderNo));//暫停Trigger
return "";
}
@PostMapping("/resume")
@ApiOperation(value = "定時任務_恢復", notes = "恢復")
@ResponseBody
public Object resume(@RequestParam("orderNo") String orderNo) throws IOException, SchedulerException {
scheduler.resumeTrigger(TriggerKey.triggerKey(orderNo));//恢復Trigger
return "ok";
}
@PostMapping("/del")
@ApiOperation(value = "定時任務_刪除", notes = "刪除")
@ResponseBody
public Object del(@RequestParam("orderNo") String orderNo) throws IOException, SchedulerException {
scheduler.pauseTrigger(TriggerKey.triggerKey(orderNo));//暫停觸發器
scheduler.unscheduleJob(TriggerKey.triggerKey(orderNo));//移除觸發器
scheduler.deleteJob(JobKey.jobKey(orderNo));//刪除Job
return "ok";
}
完事。。。。。。,如果想讓定時任務在啟動專案後自動啟動,則需要持久化任務,可以把基本資訊儲存在資料庫,專案啟動時啟動完,或者做分散式任務。
PS:歡迎在留言區留 下你的觀點,一起討論提高。如果今天的文章讓你有新的啟發,歡迎轉發分享給更多人。
猜你還想看
任正非在榮耀送別會上的講話:一旦“離婚”就不要藕斷絲連,要做華為全球最強的競爭對手
嘿,你在看嗎?
- HTML及CSS筆記
- CNCF宣佈Open Policy Agent正式畢業!
- 獨家 | 利用Python實現主題建模和LDA 演算法(附連結)
- 一行程式碼引來的安全漏洞就讓我們丟失了整個伺服器的控制權
- bzoj3289: Mato的檔案管理(莫隊 樹狀陣列)
- 橡皮擦和 TA 在 CSDN 的精英好友們,頂級大佬推薦清單
- 吳恩達深度學習學習筆記——C1W2——神經網路基礎——作業1——Python及Numpy基礎
- k8s交付服務總結
- 物理史上的八大名人
- Java遍歷Map集合方法
- HaaS100 開發除錯系列 之 CPU利用率(cpuusage)的原理與使用
- Ceph 壞盤
- N51期第四次作業
- 帶BlendShape表情的動作檔案播放異常
- 系統開發基礎:UML相關知識筆記
- 雜湊表的實現
- 關於Docker、Docker Engine和Kubernetes v1.20,開發人員需要了解的一切
- Java第九次作業
- 最厲害的VUE指令,看完你就會了!!!
- SpringBoot整合Quartz實現定時任務的動態建立、啟動、暫停、恢復、刪除。