Quartz定時任務(wù)管理方式(動態(tài)添加、停止、恢復(fù)、刪除定時任務(wù))
Quartz定時任務(wù)框架經(jīng)常用于系統(tǒng)后臺業(yè)務(wù)異步處理。平常我們使用時,主要是通過手工編寫配置代碼文件方式添加修改定時任務(wù),然后重啟系統(tǒng)。
有時候我們需要根據(jù)業(yè)務(wù)運營需要,動態(tài)添加修改定時任務(wù),比如添加新的定時任務(wù)、修改任務(wù)執(zhí)行時間、暫停定時任務(wù)、刪除定時任務(wù)等,并且監(jiān)控定時任務(wù)狀態(tài),而又不想重啟系統(tǒng),這時就需要系統(tǒng)具備動態(tài)管理定時任務(wù)的功能。
Quartz提供了一系列組件,支持動態(tài)管理定時任務(wù)的功能。
Quartz定時任務(wù)主要由Scheduler、JobDetail、CronTrigger、Cron組成,實現(xiàn)動態(tài)管理定時任務(wù),主要就是通過管理上述對象來實現(xiàn)的。
1、數(shù)據(jù)庫設(shè)計
主要將我們平時配置的任務(wù)計劃放入數(shù)據(jù)庫中保存。在啟動任務(wù)是,從數(shù)據(jù)庫中查找任務(wù)計劃信息,并動態(tài)配置進(jìn)去即可。
DROP TABLE IF EXISTS `cc_task_info`; CREATE TABLE `cc_task_info` ( `TID` int(11) NOT NULL AUTO_INCREMENT, `TASK_ANME` varchar(50) NOT NULL, `TASK_CODE` varchar(50) NOT NULL, `JOB_CLASS` varchar(200) NOT NULL, `JOB_GROUP` varchar(50) NOT NULL, `CRON` varchar(50) NOT NULL, `DEL_STATUS` varchar(2) DEFAULT '1' NULL, `CRT_TIME` datetime DEFAULT NULL, PRIMARY KEY (`TID`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='定時任務(wù)管理表'; DROP TABLE IF EXISTS `cc_task_record`; CREATE TABLE `cc_task_record` ( `RID` int(11) NOT NULL AUTO_INCREMENT, `TASK_CODE` varchar(50) NOT NULL, `RUN_TIME` datetime NOT NULL, `RUN_CODE` char(1) NOT NULL, `RUN_MSG` varchar(100) NULL, PRIMARY KEY (`RID`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='定時任務(wù)運行記錄表'; DROP TABLE IF EXISTS `cc_task_status`; CREATE TABLE `cc_task_status` ( `TASK_CODE` varchar(50) NOT NULL, `TASK_STATUS` varchar(10) NOT NULL, `LST_SUCC_TIME` datetime NOT NULL, `LST_TIME` datetime NOT NULL, PRIMARY KEY (`TASK_CODE`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='定時任務(wù)運行狀態(tài)表';
2、定時任務(wù)管理
定時任務(wù)管理主要是通過Scheduler的方法來實現(xiàn)。Scheduler提供了一系列方法來管理定時任務(wù)的執(zhí)行狀態(tài)。
主要包括:
- scheduleJob():添加定時任務(wù)
- rescheduleJob():修改定時任務(wù)
- pauseJob():暫停定時任務(wù)執(zhí)行
- resumeJob():恢復(fù)定時任務(wù)執(zhí)行
- deleteJob():刪除定時任務(wù)執(zhí)行
針對上述方法,我們只需要傳入對應(yīng)參數(shù)即可。
這里我建了一個QuartzService來管理定時任務(wù),供業(yè)務(wù)層調(diào)用。
詳細(xì)代碼如下:
/**
* 定時任務(wù)管理服務(wù)
*/
@Service
public class QuartzService {
public static String SCHEDULER_OPR_START = "start";
public static String SCHEDULER_OPR_PAUSE = "pause";
public static String SCHEDULER_OPR_RESUME = "resume";
public static String SCHEDULER_OPR_REMOVE = "remove";
@Autowired
private Scheduler scheduler;
/**
* 啟動任務(wù)
*/
public void startJob(String taskCode, String taskAnme, String cron, String jobGroup,
String className) throws Exception{
Class<Job> jobClass = null;
try {
jobClass = (Class<Job>) Class.forName(className);//獲取任務(wù)執(zhí)行類
} catch (ClassNotFoundException e) {
throw new Exception("任務(wù)類不存在");
}
//創(chuàng)建job,指定job名稱和分組
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(taskCode, jobGroup).build();
//創(chuàng)建表達(dá)式工作計劃
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
//創(chuàng)建觸發(fā)器
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(taskCode, jobGroup)
.withSchedule(cronScheduleBuilder).build();
scheduler.scheduleJob(jobDetail, cronTrigger);
}
/**
* 修改定時任務(wù)執(zhí)行時間
* @param taskCode
* @param jobGroup
* @param cron 新的時間
* @throws Exception
*/
public void modifyJob(String taskCode, String jobGroup, String cron) throws Exception{
TriggerKey triggerKey = new TriggerKey(taskCode, jobGroup);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
String oldCron = trigger.getCronExpression();
if(!oldCron.equals(cron)){
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(taskCode, jobGroup)
.withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
Date date = scheduler.rescheduleJob(triggerKey, cronTrigger);
if(date == null){
throw new Exception("修改定時任務(wù)執(zhí)行時間報錯");
}
}
}
/**
* 暫停某個定時任務(wù)(任務(wù)恢復(fù)后,暫停時間段內(nèi)未執(zhí)行的任務(wù)會繼續(xù)執(zhí)行,如暫停時間段內(nèi)有2次,則會執(zhí)行2次)
* @param taskCode
* @param jobGroup
* @throws Exception
*/
public void pauseJob(String taskCode, String jobGroup) throws Exception{
JobKey jobKey = new JobKey(taskCode, jobGroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if(jobDetail == null){
return;
}
scheduler.pauseJob(jobKey);
}
/**
* 恢復(fù)某個定時任務(wù)
* @param taskCode
* @param jobGroup
* @throws Exception
*/
public void resumeJob(String taskCode, String jobGroup) throws Exception{
JobKey jobKey = new JobKey(taskCode, jobGroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if(jobDetail == null){
return;
}
scheduler.resumeJob(jobKey);
}
/**
* 刪除某個定時任務(wù)
* @param taskCode
* @param jobGroup
* @throws Exception
*/
public void deleteJob(String taskCode, String jobGroup) throws Exception{
JobKey jobKey = new JobKey(taskCode, jobGroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if(jobDetail == null){
return;
}
scheduler.deleteJob(jobKey);
}
}
3、編寫任務(wù)類JOB
任務(wù)類JOB就是定時任務(wù)具體要處理的系統(tǒng)業(yè)務(wù)邏輯,需要實現(xiàn)Job接口。
在任務(wù)啟動時,通過jobClass傳入JobDetail。
public class DemoJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
String taskCode = jobExecutionContext.getJobDetail().getKey().getName();
System.out.println("執(zhí)行定時任務(wù):" + taskCode);
}
}
4、配置Scheduler
在Configuration中配置Scheduler實例,并啟動。
@Configuration
public class QuartzConfig {
@Bean
public Scheduler scheduler(){
Scheduler scheduler = null;
SchedulerFactory factory = new StdSchedulerFactory();
try {
scheduler = factory.getScheduler();
} catch (SchedulerException e) {
e.printStackTrace();
}
if(scheduler != null){
try {
//啟動定時任務(wù)
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
return scheduler;
}
}
5、編寫API接口
通過Controller提供API接口,這里我的TaskService調(diào)用了QartzService的對應(yīng)接口,并做了一個寫數(shù)據(jù)庫讀寫操作,主要記錄定時任務(wù)狀態(tài)、執(zhí)行記錄信息的等。
@RestController
@RequestMapping("/api/task")
public class TaskController {
@Autowired
private TaskService service;
@RequestMapping("/start")
public Object start(int id){
try {
service.startJob(id);
return RtnData.ok();
} catch (Exception e) {
return RtnData.fail(e.getMessage());
}
}
@RequestMapping("/pause")
public Object pause(int id){
try {
service.pauseJob(id);
return RtnData.ok();
} catch (Exception e) {
return RtnData.fail(e.getMessage());
}
}
@RequestMapping("/resume")
public Object resume(int id){
try {
service.resumeJob(id);
return RtnData.ok();
} catch (Exception e) {
return RtnData.fail(e.getMessage());
}
}
@RequestMapping("/remove")
public Object remove(int id){
try {
service.deleteJob(id);
return RtnData.ok();
} catch (Exception e) {
return RtnData.fail(e.getMessage());
}
}
}
6、接口測試
先在數(shù)據(jù)庫中將DemoJob添加到任務(wù)管理表中,然后使用postman調(diào)用api進(jìn)行任務(wù)啟動、修改、暫停、恢復(fù)、刪除等操作,觀察系統(tǒng)后臺日志打印情況查看效果。
數(shù)據(jù)庫初始化如下:

總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
簡單談?wù)凾hreadPoolExecutor線程池之submit方法
下面小編就為大家?guī)硪黄唵握務(wù)凾hreadPoolExecutor線程池之submit方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06
Java中的異常處理(try,catch,finally,throw,throws)
本文主要介紹了Java中的異常處理,文章主要介紹的異常處理包括5個關(guān)鍵字try,catch,finally,throw,throws,更多詳細(xì)內(nèi)容需要的朋友可以參考一下2022-06-06
springboot 如何解決static調(diào)用service為null
這篇文章主要介紹了springboot 如何解決static調(diào)用service為null的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
Mybatis獲取自增主鍵的兩種實現(xiàn)原理小結(jié)
MyBatis通過useGeneratedKeys和兩種方式適配不同數(shù)據(jù)庫的自增主鍵生成,利用JDBC接口和KeyGenerator實現(xiàn)高效獲取與回寫,下面就來介紹一下2025-08-08
Spring AI TikaDocumentReader詳解
TikaDocumentReader是SpringAI中用于從多種格式文檔中提取文本內(nèi)容的組件,支持PDF、DOC/DOCX、PPT/PPTX和HTML等格式,它在構(gòu)建知識庫、文檔處理和數(shù)據(jù)清洗等任務(wù)中非常有用2025-01-01
java Class文件內(nèi)部結(jié)構(gòu)解析過程詳解
java class的文件結(jié)構(gòu),java class文件結(jié)構(gòu)是基于字節(jié)流的,用unicode進(jìn)行編碼,下面說說java Class文件內(nèi)部結(jié)構(gòu)分析2013-11-11

