SpringBoot3集成Quartz

标签:Quartz.Job.Scheduler;

一、简介

Quartz由Java编写的功能丰富的开源作业调度框架,可以集成到几乎任何Java应用程序中,并且能够创建多个作业调度;

在实际的业务中,有很多场景依赖定时任务,比如常见的:订单超时处理,数据报表统计分析,会员等周期性管理,业务识别和预警通知等;

二、工程搭建

1、工程结构

2、依赖管理

starter-quartz组件中,实际依赖的是quartz组件2.3.2版本,使用Quartz框架时,需要自定义任务和执行逻辑,以更加灵活的方式管理业务调度;

<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任务执行日志表;

4、配置文件

在配置文件中使用Druid组件连接boot-quartz数据库,对于Quartz框架,主要配置数据库存储,调度器的基础信息,以及执行任务的线程池;

spring:# 定时器配置quartz:# 使用数据库存储job-store-type: jdbc# 初始化完成后自动启动调度程序autoStartup: trueproperties:org:quartz:# 调度器配置scheduler:instanceName: bootQuartzSchedulerinstanceId: AUTO# 存储配置jobStore:class: org.springframework.scheduling.quartz.LocalDataSourceJobStoredriverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegatetablePrefix: qrtz_isClustered: truemisfireThreshold: 12000clusterCheckinInterval: 15000useProperties: false# 线程池配置threadPool:threadNamePrefix: Boot_Job_PoolthreadPriority: 5threadCount: 10class: org.quartz.simpl.SimpleThreadPool

三、Quartz用法

对于任务管理的相关Web接口,采用Swagger文档组件,接口和实体类添加注解后,访问IP:Port/swagger-ui/index.html地址即可;

1、初始化加载

在服务启动时执行init初始化方法,查询quartz_job表中运行和暂停状态的任务,判断触发器是否存在,如果不存在则创建,如果存在则更新;

@Service
public class QuartzJobService {@Resourceprivate QuartzJobMapper quartzJobMapper ;@Resourceprivate QuartzManage quartzManage;@PostConstructpublic 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、新增任务

在创建任务时,需要定义JobKeyTriggerKey的构建规则,Key需要具备唯一性,通常使用任务表的主键ID,任务一般是基于Cron表达式被调度执行的;

@Component
public class QuartzManage {@Resourceprivate 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() ;// 任务触发器CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(quartzJob.getId())).withSchedule(scheduleBuilder).build() ;jobDetail.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY,quartzJob);scheduler.scheduleJob(jobDetail,trigger) ;// 状态校验checkStop(quartzJob) ;} catch (SchedulerException e){throw new RuntimeException("createJob Fail",e) ;}}
}

3、更新任务

先通过任务ID查询TriggerKey,对于更新来说,最常见的就是Cron表达式即调度规则的更新,或者任务的执行参数更新;

@Component
public class QuartzManage {@Resourceprivate Scheduler scheduler ;public void updateJob(QuartzJob quartzJob) {try {// 查询触发器KeyTriggerKey triggerKey = getTriggerKey(quartzJob.getId());// 构建Cron调度器CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpres()).withMisfireHandlingInstructionDoNothing();// 任务触发器CronTrigger trigger = getCronTrigger(quartzJob.getId()).getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();trigger.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY, quartzJob);scheduler.rescheduleJob(triggerKey, trigger);// 状态校验checkStop(quartzJob) ;} catch (SchedulerException e) {throw new RuntimeException("updateJob Fail",e) ;}}
}

4、暂停任务

先通过任务ID查询JobKey,判断任务是非运行状态,则停止任务;

@Component
public class QuartzManage {@Resourceprivate 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,恢复任务正常执行;

@Component
public class QuartzManage {@Resourceprivate Scheduler scheduler ;public void resumeJob (Integer jobId){try {this.scheduler.resumeJob(getJobKey(jobId));} catch (SchedulerException e){throw new RuntimeException("resumeJob Fail",e) ;}}
}

6、执行一次

传入任务主体,再通过任务ID查询JobKey,然后立即执行一次任务;

@Component
public class QuartzManage {@Resourceprivate 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 {@Resourceprivate Scheduler scheduler ;public void deleteJob (Integer jobId){try {scheduler.deleteJob(getJobKey(jobId));} catch (SchedulerException e){throw new RuntimeException("deleteJob Fail",e) ;}}
}

8、任务执行

Quartz被集成在Spring框架之后,任务类自然会以Bean对象的方式被管理,在任务创建时,设置要执行的作业类QuartzRecord,该类继承QuartzJobBean抽象类,通过重写executeInternal方法,来管理任务实际执行的逻辑;

public class QuartzRecord extends QuartzJobBean {@Overrideprotected 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 {// 加载并执行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 {// 保存执行日志quartzLogService.insert(quartzLog) ;}}
}

四、参考源码

文档仓库:
https://gitee.com/cicadasmile/butte-java-note源码仓库:
https://gitee.com/cicadasmile/butte-spring-parent

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/87496.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java SpringBoot 加载 yml 配置文件中字典项

实际项目中&#xff0c;如果将该类信息放配置文件中的话&#xff0c;一般会结合Nocas一起使用 将字典数据&#xff0c;配置在 yml 文件中&#xff0c;通过加载yml将数据加载到 Map中 Spring Boot 中 yml 配置、引用其它 yml 中的配置。# 在配置文件目录&#xff08;如&#xff…

Ajax-概念、Http协议、Ajax请求及其常见问题

Ajax Ajax概念Ajax优缺点HTTP协议请求报文响应报文 Ajax案例准备工作express基本使用创建一个服务器 发送AJAX请求GET请求POST请求JSON响应 Ajax请求出现的问题IE缓存问题Ajax请求超时与网络异常处理Ajax手动取消请求Ajax重复发送请求问题 Ajax概念 AJAX 全称为Asynchronous J…

Maven从入门到好难

参考文献 永远最好的官网 超赞maven系列文章 1. 为啥要有maven 想当初&#xff0c;刚毕业刚工作&#xff0c;之前学的C&#xff0c;java不懂&#xff0c;部门用的Spring&#xff0c;于是开始学习SSM&#xff0c;妈的&#xff0c;jar包好难整&#xff0c;还要一个个下载好放到…

腾讯云服务器标准型CVM实例详细介绍S5/S6/SA2/SR1/SA3/S4等

腾讯云CVM服务器标准型实例的各项性能参数平衡&#xff0c;标准型云服务器适用于大多数常规业务&#xff0c;例如&#xff1a;web网站及中间件等&#xff0c;常见的标准型云服务器有CVM标准型S5、S6、SA3、SR1、S5se等规格&#xff0c;腾讯云服务器网来详细说下云服务器CVM标准…

HCIP BGP实验

题目 拓扑图 配置IP地址及环回 R1 <Huawei>sy Enter system view, return user view with CtrlZ. [Huawei]sysname r1 [r1]int l0 [r1-LoopBack0]ip add 1.1.1.1 24 [r1-LoopBack0]int g0/0/0 [r1-GigabitEthernet0/0/0]ip add 12.1.1.1 24R2 <Huawei>sy Enter …

AI lightning学习

真的是没有mmlab的框架好理解&#xff0c;hook调用没问题&#xff0c;就是代码写的不整洁&#xff0c;hook放的到处都是&#xff0c;而且hook的名字和run的名字也不好对应。 又是捧mmengine的一天 &#x1f603;

2023国赛数学建模A题B题C题D题E题思路分析 2023全国大学生数学建模思路

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 全国大学生数学建模…

jupyter文档转换成markdown

背景 上一篇文章**《如何优雅地用python生成模拟数据》**我就使用jupyter写的&#xff0c;这个真的是万能的&#xff0c;可以插入markdown格式的内容&#xff0c;也可写代码&#xff0c;关键是像ipython一样&#xff0c;可以分步执行。 我可以这样自由的写我的博客内容&#x…

div 中元素居中的N种常用方法

本文主要记录几种常用的div盒子水平垂直都居中的方法。本文主要参考了该篇博文并实践加以记录说明以加深理解记忆 css之div盒子居中常用方法大全 本文例子使用的 html body结构下的div 盒子模型如下&#xff1a; <body><div class"container"><div c…

论文阅读:《Waymo Public Road Safety Performance Data》

文章目录 1 背景2 方法2.1 数据来源2.2 碰撞数据 3 碰撞事件分析4 讨论 1 背景 这篇文章是讲waymo道路安全性能数据分析的&#xff0c;主要想表达的是waymo自动驾驶系统在安全上面的出色表现&#xff0c;以向政府、大众提高自己产品的公信力。 这篇文章分析的数据是自从2019年到…

备战秋招012(20230808)

文章目录 前言一、今天学习了什么&#xff1f;二、动态规划1.概念2.题目 总结 前言 提示&#xff1a;这里为每天自己的学习内容心情总结&#xff1b; Learn By Doing&#xff0c;Now or Never&#xff0c;Writing is organized thinking. 提示&#xff1a;以下是本篇文章正文…

Vue主面板组件模板(简洁版)

文章目录 &#x1f412;个人主页&#x1f3c5;JavaEE系列专栏&#x1f4d6;前言&#xff1a;&#x1f380;源码如下&#xff1a; &#x1f412;个人主页 &#x1f3c5;JavaEE系列专栏 &#x1f4d6;前言&#xff1a; 本篇博客主要以介绍【&#x1f380;主面板组件模板&#xf…

【计算机视觉|生成对抗】用深度卷积生成对抗网络进行无监督表示学习(DCGAN)

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks 链接&#xff1a;[1511.06434] Unsupervised Representation Learning with Deep Conv…

Webpack 的 sass-loader 在生产模式下最小化 CSS 问题

学习webpack时候我发现一个问题&#xff1a; 将mode 改为production模式后&#xff0c;生成的css会被压缩了&#xff0c;但是我并没有引入CssMinimizerPlugin插件&#xff0c;然后我试着将optimization.minimize 设置为false&#xff0c;测试是否为webpack自带的压缩&#xff0…

设备工单管理系统如何实现工单流程自动化?

设备工单管理系统属于工单系统的一种&#xff0c;基于其丰富的功能&#xff0c;它可以同时处理不同的多组流程&#xff0c;旨在有效处理发起人提交的事情&#xff0c;指派相应人员完成服务请求和记录全流程。该系统主要面向后勤管理、设备维护、物业管理、酒店民宿等服务行业设…

九、解析应用程序——分析应用程序(2)

文章目录 一、确定服务器端功能二、解析受攻击面 一、确定服务器端功能 通过留意应用程序向客户端披露的线索&#xff0c;通常可推断与服务器端功能和结构有关的大量信息&#xff0c;或者至少可做出有根据的猜测。以下面用于访问搜索功能的URL为例: 可见&#xff0c;.jsp文件扩…

选择最适合自己的笔记本

选择最适合自己的笔记本电脑 一、了解笔记本品牌一线品牌准一线品牌二线品牌三线品牌 二、笔记本入手渠道笔记本入手渠道 三、根据需求选择机型使用需求1.日常使用2.商务办公、财务3.轻度剪辑、ps4.代码5.创意设计6.游戏 四、笔记本电脑配置如何选1.cpu2.显卡&#xff08;GPU&a…

数据结构:力扣OJ题

目录 ​编辑题一&#xff1a;链表分割 思路一&#xff1a; 题二&#xff1a;相交链表 思路一&#xff1a; 题三&#xff1a;环形链表 思路一&#xff1a; 题四&#xff1a;链表的回文结构 思路一&#xff1a; 链表反转&#xff1a; 查找中间节点&#xff1a; 本人实力…

数字鸿沟,让气候脆弱者更脆弱

“从小到大完全没敢想&#xff0c;也觉得是不可思议的一件事儿&#xff0c;发洪水发到家门口了”&#xff0c;前两天&#xff0c;一位门头沟土著友人&#xff0c;给我发来了这句话。 气候变化正在影响整个地球&#xff0c;面对一连串前所未见的极端天气灾害&#xff0c;很多人应…

CCLINK IE FIELD BASIC转MODBUS-TCP网关cclink与以太网的区别

协议的不同&#xff0c;数据读取困难&#xff0c;这是很多生产管理系统的难题。但是现在&#xff0c;捷米JM-CCLKIE-TCP通讯网关&#xff0c;让这个问题变得非常简单。这款通讯网关可以将各种MODBUS-TCP设备接入到CCLINK IE FIELD BASIC网络中&#xff0c;连接到MODBUS-TCP总线…