SpringBoot3集成Quartz的示例代碼
一、簡介
Quartz由Java編寫的功能豐富的開源作業(yè)調(diào)度框架,可以集成到幾乎任何Java應(yīng)用程序中,并且能夠創(chuàng)建多個作業(yè)調(diào)度;
在實(shí)際的業(yè)務(wù)中,有很多場景依賴定時任務(wù),比如常見的:訂單超時處理,數(shù)據(jù)報表統(tǒng)計(jì)分析,會員等周期性管理,業(yè)務(wù)識別和預(yù)警通知等;
二、工程搭建
1、工程結(jié)構(gòu)
2、依賴管理
在 starter-quartz
組件中,實(shí)際依賴的是 quartz
組件 2.3.2
版本,使用Quartz框架時,需要自定義任務(wù)和執(zhí)行邏輯,以更加靈活的方式管理業(yè)務(wù)調(diào)度;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> <version>${spring-boot.version}</version> </dependency>
3、數(shù)據(jù)庫
Quartz框架使用的表結(jié)構(gòu)在如圖的路徑下,本文選擇MySQL數(shù)據(jù)庫存儲,除此之外自定義兩張表: quartz_job
任務(wù)表和 quartz_log
任務(wù)執(zhí)行日志表;
4、配置文件
在配置文件中使用Druid組件連接 boot-quartz
數(shù)據(jù)庫,對于Quartz框架,主要配置數(shù)據(jù)庫存儲,調(diào)度器的基礎(chǔ)信息,以及執(zhí)行任務(wù)的線程池;
spring: # 定時器配置 quartz: # 使用數(shù)據(jù)庫存儲 job-store-type: jdbc # 初始化完成后自動啟動調(diào)度程序 autoStartup: true properties: org: quartz: # 調(diào)度器配置 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用法
對于任務(wù)管理的相關(guān)Web接口,采用Swagger文檔組件,接口和實(shí)體類添加注解后,訪問 IP:Port/swagger-ui/index.html
地址即可;
1、初始化加載
在服務(wù)啟動時執(zhí)行 init
初始化方法,查詢 quartz_job
表中運(yùn)行和暫停狀態(tài)的任務(wù),判斷觸發(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、新增任務(wù)
在創(chuàng)建任務(wù)時,需要定義 JobKey
和 TriggerKey
的構(gòu)建規(guī)則,Key需要具備唯一性,通常使用任務(wù)表的主鍵ID,任務(wù)一般是基于Cron表達(dá)式被調(diào)度執(zhí)行的;
@Component public class QuartzManage { @Resource private Scheduler scheduler ; public void createJob (QuartzJob quartzJob){ try { // 構(gòu)建任務(wù) JobDetail jobDetail = JobBuilder.newJob(QuartzRecord.class).withIdentity(getJobKey(quartzJob.getId())).build() ; // 構(gòu)建Cron調(diào)度器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder .cronSchedule(quartzJob.getCronExpres()) .withMisfireHandlingInstructionDoNothing() ; // 任務(wù)觸發(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)校驗(yàn) checkStop(quartzJob) ; } catch (SchedulerException e){ throw new RuntimeException("createJob Fail",e) ; } } }
3、更新任務(wù)
先通過任務(wù)ID查詢 TriggerKey
,對于更新來說,最常見的就是Cron表達(dá)式即調(diào)度規(guī)則的更新,或者任務(wù)的執(zhí)行參數(shù)更新;
@Component public class QuartzManage { @Resource private Scheduler scheduler ; public void updateJob(QuartzJob quartzJob) { try { // 查詢觸發(fā)器Key TriggerKey triggerKey = getTriggerKey(quartzJob.getId()); // 構(gòu)建Cron調(diào)度器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder .cronSchedule(quartzJob.getCronExpres()) .withMisfireHandlingInstructionDoNothing(); // 任務(wù)觸發(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)校驗(yàn) checkStop(quartzJob) ; } catch (SchedulerException e) { throw new RuntimeException("updateJob Fail",e) ; } } }
4、暫停任務(wù)
先通過任務(wù)ID查詢 JobKey
,判斷任務(wù)是非運(yùn)行狀態(tài),則停止任務(wù);
@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、恢復(fù)任務(wù)
先通過任務(wù)ID查詢 JobKey
,恢復(fù)任務(wù)正常執(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í)行一次
傳入任務(wù)主體,再通過任務(wù)ID查詢 JobKey
,然后立即執(zhí)行一次任務(wù);
@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、刪除任務(wù)
先通過任務(wù)ID查詢 JobKey
,徹底刪除任務(wù);
@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、任務(wù)執(zhí)行
Quartz被集成在Spring框架之后,任務(wù)類自然會以Bean對象的方式被管理,在任務(wù)創(chuàng)建時,設(shè)置要執(zhí)行的作業(yè)類 QuartzRecord
,該類繼承 QuartzJobBean
抽象類,通過重寫 executeInternal
方法,來管理任務(wù)實(shí)際執(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的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot3集成Quartz的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java中tomcat memecached session 共享同步問題的解決辦法
這篇文章主要介紹了Java中tomcat memecached session 共享同步問題的解決辦法的相關(guān)資料,需要的朋友可以參考下2015-10-10Spring Validation和Hibernate Validator結(jié)合國際化代碼實(shí)例
這篇文章主要介紹了Spring Validation和Hibernate Validator結(jié)合國際化代碼實(shí)例,我們需要對請求參數(shù)進(jìn)行非空、長度、正確性進(jìn)行校驗(yàn), 本文主要講解Spring Validation 和 Hibernate Validator, 同時整合i18n(國際化)實(shí)現(xiàn)參數(shù)校驗(yàn)自動,需要的朋友可以參考下2023-10-10IDEA之web項(xiàng)目導(dǎo)入jar包方式
這篇文章主要介紹了IDEA之web項(xiàng)目導(dǎo)入jar包方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05springboot接收http請求,解決參數(shù)中+號變成空格的問題
這篇文章主要介紹了springboot接收http請求,解決參數(shù)中+號變成空格的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08SpringBoot 如何使用RestTemplate發(fā)送Post請求
這篇文章主要介紹了SpringBoot 如何使用RestTemplate發(fā)送Post請求的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08Java swing實(shí)現(xiàn)的計(jì)算器功能完整實(shí)例
這篇文章主要介紹了Java swing實(shí)現(xiàn)的計(jì)算器功能,結(jié)合完整實(shí)例形式分析了java基于swing組件實(shí)現(xiàn)計(jì)算器布局與運(yùn)算功能的具體操作技巧,需要的朋友可以參考下2017-12-12分享Java程序員應(yīng)該知道的10個調(diào)試技巧
在本文中,作者將使用大家常用的的開發(fā)工具Eclipse來調(diào)試Java應(yīng)用程序。但這里介紹的調(diào)試方法基本都是通用的,也適用于NetBeans IDE,我們會把重點(diǎn)放在運(yùn)行時上面2012-09-09歸并算法之有序數(shù)組合并算法實(shí)現(xiàn)
這篇文章主要介紹了歸并算法之有序數(shù)組合并算法實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-07-07