SpringBoot3集成Quartz的示例代碼
一、簡介
Quartz由Java編寫的功能豐富的開源作業(yè)調度框架,可以集成到幾乎任何Java應用程序中,并且能夠創(chuàng)建多個作業(yè)調度;
在實際的業(yè)務中,有很多場景依賴定時任務,比如常見的:訂單超時處理,數據報表統(tǒng)計分析,會員等周期性管理,業(yè)務識別和預警通知等;
二、工程搭建
1、工程結構

2、依賴管理
在 starter-quartz 組件中,實際依賴的是 quartz 組件 2.3.2 版本,使用Quartz框架時,需要自定義任務和執(zhí)行邏輯,以更加靈活的方式管理業(yè)務調度;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
<version>${spring-boot.version}</version>
</dependency>3、數據庫
Quartz框架使用的表結構在如圖的路徑下,本文選擇MySQL數據庫存儲,除此之外自定義兩張表: quartz_job 任務表和 quartz_log 任務執(zhí)行日志表;

4、配置文件
在配置文件中使用Druid組件連接 boot-quartz 數據庫,對于Quartz框架,主要配置數據庫存儲,調度器的基礎信息,以及執(zhí)行任務的線程池;
spring:
# 定時器配置
quartz:
# 使用數據庫存儲
job-store-type: jdbc
# 初始化完成后自動啟動調度程序
autoStartup: true
properties:
org:
quartz:
# 調度器配置
scheduler:
instanceName: bootQuartzScheduler
instanceId: AUTO
# 存儲配置
jobStore:
class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
tablePrefix: qrtz_
isClustered: true
misfireThreshold: 12000
clusterCheckinInterval: 15000
useProperties: false
# 線程池配置
threadPool:
threadNamePrefix: Boot_Job_Pool
threadPriority: 5
threadCount: 10
class: org.quartz.simpl.SimpleThreadPool三、Quartz用法
對于任務管理的相關Web接口,采用Swagger文檔組件,接口和實體類添加注解后,訪問 IP:Port/swagger-ui/index.html 地址即可;

1、初始化加載
在服務啟動時執(zhí)行 init 初始化方法,查詢 quartz_job 表中運行和暫停狀態(tài)的任務,判斷觸發(fā)器是否存在,如果不存在則創(chuàng)建,如果存在則更新;
@Service
public class QuartzJobService {
@Resource
private QuartzJobMapper quartzJobMapper ;
@Resource
private QuartzManage quartzManage;
@PostConstruct
public void init () {
LambdaQueryWrapper<QuartzJob> queryWrapper = new LambdaQueryWrapper<>() ;
queryWrapper.in(QuartzJob::getState,JobState.JOB_RUN.getStatus(),JobState.JOB_STOP.getStatus());
List<QuartzJob> jobList = quartzJobMapper.selectList(queryWrapper);
jobList.forEach(quartzJob -> {
CronTrigger cronTrigger = quartzManage.getCronTrigger(quartzJob.getId()) ;
if (Objects.isNull(cronTrigger)){
quartzManage.createJob(quartzJob);
} else {
quartzManage.updateJob(quartzJob);
}
});
}
}2、新增任務
在創(chuàng)建任務時,需要定義 JobKey 和 TriggerKey 的構建規(guī)則,Key需要具備唯一性,通常使用任務表的主鍵ID,任務一般是基于Cron表達式被調度執(zhí)行的;
@Component
public class QuartzManage {
@Resource
private Scheduler scheduler ;
public void createJob (QuartzJob quartzJob){
try {
// 構建任務
JobDetail jobDetail = JobBuilder.newJob(QuartzRecord.class).withIdentity(getJobKey(quartzJob.getId())).build() ;
// 構建Cron調度器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
.cronSchedule(quartzJob.getCronExpres())
.withMisfireHandlingInstructionDoNothing() ;
// 任務觸發(fā)器
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(quartzJob.getId()))
.withSchedule(scheduleBuilder).build() ;
jobDetail.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY,quartzJob);
scheduler.scheduleJob(jobDetail,trigger) ;
// 狀態(tài)校驗
checkStop(quartzJob) ;
} catch (SchedulerException e){
throw new RuntimeException("createJob Fail",e) ;
}
}
}3、更新任務
先通過任務ID查詢 TriggerKey ,對于更新來說,最常見的就是Cron表達式即調度規(guī)則的更新,或者任務的執(zhí)行參數更新;
@Component
public class QuartzManage {
@Resource
private Scheduler scheduler ;
public void updateJob(QuartzJob quartzJob) {
try {
// 查詢觸發(fā)器Key
TriggerKey triggerKey = getTriggerKey(quartzJob.getId());
// 構建Cron調度器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
.cronSchedule(quartzJob.getCronExpres())
.withMisfireHandlingInstructionDoNothing();
// 任務觸發(fā)器
CronTrigger trigger = getCronTrigger(quartzJob.getId())
.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
trigger.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY, quartzJob);
scheduler.rescheduleJob(triggerKey, trigger);
// 狀態(tài)校驗
checkStop(quartzJob) ;
} catch (SchedulerException e) {
throw new RuntimeException("updateJob Fail",e) ;
}
}
}4、暫停任務
先通過任務ID查詢 JobKey ,判斷任務是非運行狀態(tài),則停止任務;
@Component
public class QuartzManage {
@Resource
private Scheduler scheduler ;
public void checkStop (QuartzJob quartzJob){
try {
if(quartzJob.getState() != JobState.JOB_RUN.getStatus()){
this.scheduler.pauseJob(getJobKey(quartzJob.getId()));
}
} catch (SchedulerException e){
throw new RuntimeException("pauseJob Fail",e) ;
}
}
}5、恢復任務
先通過任務ID查詢 JobKey ,恢復任務正常執(zhí)行;
@Component
public class QuartzManage {
@Resource
private Scheduler scheduler ;
public void resumeJob (Integer jobId){
try {
this.scheduler.resumeJob(getJobKey(jobId));
} catch (SchedulerException e){
throw new RuntimeException("resumeJob Fail",e) ;
}
}
}6、執(zhí)行一次
傳入任務主體,再通過任務ID查詢 JobKey ,然后立即執(zhí)行一次任務;
@Component
public class QuartzManage {
@Resource
private Scheduler scheduler ;
public void run (QuartzJob quartzJob){
try {
JobDataMap dataMap = new JobDataMap() ;
dataMap.put(QuartzJob.JOB_PARAM_KEY,quartzJob);
this.scheduler.triggerJob(getJobKey(quartzJob.getId()),dataMap);
} catch (SchedulerException e){
throw new RuntimeException("run Fail",e) ;
}
}
}7、刪除任務
先通過任務ID查詢 JobKey ,徹底刪除任務;
@Component
public class QuartzManage {
@Resource
private Scheduler scheduler ;
public void deleteJob (Integer jobId){
try {
scheduler.deleteJob(getJobKey(jobId));
} catch (SchedulerException e){
throw new RuntimeException("deleteJob Fail",e) ;
}
}
}8、任務執(zhí)行
Quartz被集成在Spring框架之后,任務類自然會以Bean對象的方式被管理,在任務創(chuàng)建時,設置要執(zhí)行的作業(yè)類 QuartzRecord ,該類繼承 QuartzJobBean 抽象類,通過重寫 executeInternal 方法,來管理任務實際執(zhí)行的邏輯;
public class QuartzRecord extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) {
QuartzJob quartzJob = (QuartzJob)context.getMergedJobDataMap().get(QuartzJob.JOB_PARAM_KEY) ;
QuartzLogService quartzLogService = (QuartzLogService)SpringContextUtil.getBean("quartzLogService") ;
// 定時器日志記錄
QuartzLog quartzLog = new QuartzLog () ;
quartzLog.setJobId(quartzJob.getId());
quartzLog.setBeanName(quartzJob.getBeanName());
quartzLog.setParams(quartzJob.getParams());
quartzLog.setCreateTime(new Date());
long beginTime = System.currentTimeMillis() ;
try {
// 加載并執(zhí)行
Object target = SpringContextUtil.getBean(quartzJob.getBeanName());
Method method = target.getClass().getDeclaredMethod("run", String.class);
method.invoke(target, quartzJob.getParams());
long executeTime = System.currentTimeMillis() - beginTime;
quartzLog.setTimes((int)executeTime);
quartzLog.setState(LogState.LOG_SUS.getStatus());
} catch (Exception e){
// 異常信息
long executeTime = System.currentTimeMillis() - beginTime;
quartzLog.setTimes((int)executeTime);
quartzLog.setState(LogState.LOG_FAIL.getStatus());
quartzLog.setError(e.getMessage());
} finally {
// 保存執(zhí)行日志
quartzLogService.insert(quartzLog) ;
}
}
}四、參考源碼
文檔倉庫: https://gitee.com/cicadasmile/butte-java-note 源碼倉庫: https://gitee.com/cicadasmile/butte-spring-parent
以上就是SpringBoot3集成Quartz的示例代碼的詳細內容,更多關于SpringBoot3集成Quartz的資料請關注腳本之家其它相關文章!
相關文章
Java中tomcat memecached session 共享同步問題的解決辦法
這篇文章主要介紹了Java中tomcat memecached session 共享同步問題的解決辦法的相關資料,需要的朋友可以參考下2015-10-10
Spring Validation和Hibernate Validator結合國際化代碼實例
這篇文章主要介紹了Spring Validation和Hibernate Validator結合國際化代碼實例,我們需要對請求參數進行非空、長度、正確性進行校驗, 本文主要講解Spring Validation 和 Hibernate Validator, 同時整合i18n(國際化)實現參數校驗自動,需要的朋友可以參考下2023-10-10
springboot接收http請求,解決參數中+號變成空格的問題
這篇文章主要介紹了springboot接收http請求,解決參數中+號變成空格的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
SpringBoot 如何使用RestTemplate發(fā)送Post請求
這篇文章主要介紹了SpringBoot 如何使用RestTemplate發(fā)送Post請求的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08

