SpringBoot 整合 Quartz 实现 对任务进行CRUD

前言

公司之前的项目的定时任务都是使用@Schedule注解进行管理的;新需求需要实现对定时任务进行动态管理。后面决定用Quartz框架进行集成,以最小的代码来管理定时任务。

所需依赖:Springboot  1.xx 或 2.xx-RELEASE 都行, quartz 使用2.3.0版本

        <dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.0</version></dependency>

为了简单演示,只创建一个任务类用于修改定时任务实体类即可,创建任务实体类:QuartzBean

@Data
public class QuartzBean implements Serializable {private static final long serialVersionUID=1L;@TableIdprivate String id;/*** 任务名称*/private String jobName;/*** 任务执行类*/private String jobClass;/*** 任务时间表达式*/@NotNullprivate String cron;/*** 任务启动状态 0 运行中 1 已关闭*/private Integer status;/*** 创建时间*/private Date createTime;
}

一、配置Quartz相关配置类

这里有三个配置类,分别为AutowiringSpringBeanJobFactory.java(主要是为了使得Job任务类运行时,可以注入其他service层)、QuartzConfig.java(quartz配置类,可设置对应的数据源,将schedule创建bean对象等)和 QuartzJobInitializer.java (用于项目启动时,可以从数据库里取出对应的QuartzBean对象,进行任务的自启动)

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;/*** 功能说明: job配置可注入其他服务类*/
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {private transient AutowireCapableBeanFactory beanFactory;@Overridepublic void setApplicationContext(ApplicationContext context) {beanFactory = context.getAutowireCapableBeanFactory();}@Overrideprotected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {final Object job = super.createJobInstance(bundle);beanFactory.autowireBean(job);return job;}
}


import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;/*** 功能说明: quartz配置类*/
@Configuration
public class QuartzConfig {/** 暂不使用数据库进行quartz的持久化@Beanpublic Properties properties() throws IOException {PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();// 对quartz.properties文件进行读取propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));// 在quartz.properties中的属性被读取并注入后再初始化对象propertiesFactoryBean.afterPropertiesSet();return propertiesFactoryBean.getObject();}**/@Beanpublic AutowiringSpringBeanJobFactory autowiringSpringBeanJobFactory() {return new AutowiringSpringBeanJobFactory();}@Beanpublic SchedulerFactoryBean schedulerFactoryBean() {SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();schedulerFactoryBean.setAutoStartup(true);schedulerFactoryBean.setJobFactory(autowiringSpringBeanJobFactory());// 从application.yml中读取Quartz的配置并设置到SchedulerFactoryBean中
//    schedulerFactoryBean.setQuartzProperties(properties());return schedulerFactoryBean;}/*** 通过SchedulerFactoryBean获取Scheduler的实例* @param schedulerFactoryBean* @return*/@Beanpublic Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) {return schedulerFactoryBean.getScheduler();}}
@Slf4j
@Component
public class QuartzJobInitializer {@Autowiredprivate Scheduler scheduler;@Autowiredprivate IQuartzBeanService quartzBeanService;@Autowiredpublic QuartzJobInitializer(Scheduler scheduler) {this.scheduler = scheduler;}@PostConstructpublic void init(){log.info("quartz:默认启动所有开启状态的定时任务");List<QuartzBean> quartzBeans = quartzBeanService.selectList(new EntityWrapper<>());List<QuartzBean> executeJobs = quartzBeans.stream().filter(f -> QuartzEnums.TaskStatusEnum.RUNNING.getType().equals(f.getStatus())).collect(Collectors.toList());try {// 这里将会启动所有定时任务if (CollUtil.isNotEmpty(executeJobs)) {executeJobs.forEach(item -> QuartzUtils.createScheduleJob(scheduler, item));}}catch (Exception e) {log.error("自启动定时任务异常: {}",e);}}}

二、创建QuartzUtils.java类

QuartzUtils类主要用于底层的创建、修改、删除、立即执行、暂停和恢复任务

mport com.bean.QuartzBean;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;/*** 功能说明: 定时任务执行工具类*/
@Slf4j
public class QuartzUtils {/*** 创建定时任务 定时任务创建之后默认启动状态* @param scheduler* @param quartzBean*/public static void createScheduleJob(Scheduler scheduler, QuartzBean quartzBean) {try {//获取到定时任务的执行类  必须是类的绝对路径名称//定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。Class<? extends Job> jobClass = (Class<? extends  Job>)Class.forName(quartzBean.getJobClass());// 构建定时任务信息JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzBean.getJobName()).build();// 设置定时任务执行方式CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCron());// 构建触发器triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzBean.getJobName()).withSchedule(scheduleBuilder).build();scheduler.scheduleJob(jobDetail, trigger);} catch (ClassNotFoundException e) {log.error("定时任务类路径出错:请输入类的绝对路径 {}",e.getMessage());} catch (SchedulerException e) {log.error("创建定时任务出错: {}", e.getMessage());}}/*** 根据任务名称暂停定时任务* @param scheduler* @param jobName*/public static void pauseScheduleJob(Scheduler scheduler, String jobName) {JobKey jobKey = JobKey.jobKey(jobName);try {scheduler.pauseJob(jobKey);} catch (SchedulerException e) {log.error("暂停定时任务出错: {}", e.getMessage());}}/*** 根据任务名称恢复定时任务* @param scheduler* @param jobName*/public static void resumeScheduleJob(Scheduler scheduler, String jobName) {JobKey jobKey = JobKey.jobKey(jobName);try {scheduler.resumeJob(jobKey);} catch (SchedulerException e) {System.out.println("恢复定时任务出错:"+e.getMessage());}}/*** 根据任务名称立即运行一次定时任务* @param scheduler* @param jobName*/public static void runOnce(Scheduler scheduler, String jobName){JobKey jobKey = JobKey.jobKey(jobName);try {scheduler.triggerJob(jobKey);} catch (SchedulerException e) {System.out.println("运行定时任务出错:"+e.getMessage());}}/*** 更新定时任务* @param scheduler* @param quartzBean*/public static void updateScheduleJob(Scheduler scheduler, QuartzBean quartzBean)  {try {//获取到对应任务的触发器TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName());//设置定时任务执行方式CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCron());//重新构建任务的触发器triggerCronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();//重置对应的jobscheduler.rescheduleJob(triggerKey, trigger);} catch (SchedulerException e) {System.out.println("更新定时任务出错:"+e.getMessage());}}/*** 根据定时任务名称从调度器当中删除定时任务* @param scheduler* @param jobName*/public static void deleteScheduleJob(Scheduler scheduler, String jobName) {JobKey jobKey = JobKey.jobKey(jobName);try {scheduler.deleteJob(jobKey);} catch (SchedulerException e) {System.out.println("删除定时任务出错:"+e.getMessage());}}}

三、创建任务类,即定时任务可执行的类 MyQuartzTask

import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Service;/*** 功能说明: 定时任务-MyQuartzTask*/
@Slf4j
@Service
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class MyQuartzTask extends QuartzJobBean {@Overrideprotected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {String jobName = jobExecutionContext.getJobDetail().getKey().getName();log.info("定时任务【{}】启动成功", jobName);}

四、效果演示

@Slf4j
@RestController
@RequestMapping("/quartz")
public class QuartzController {@Autowiredprivate Scheduler scheduler;/*** 创建定时任务* @param quartzVO* @return*/@GetMapping("/createScheduleJob")public ResultVO createScheduleJob() {QuartzBean quartzBean = QuartzBean.builder().jobName("任务名称唯一").jobClass("com.service.impl.quartz.MyQuartzTask").cron("0 0/2 * * * ?").build();QuartzUtils.createScheduleJob(scheduler, quartzBean);return ResultVOUtil.success();}

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

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

相关文章

CentOS升级GCC

背景 CentOS 7默认自带GCC版本4.8&#xff0c;而目前工作中开发环境需要用到GCC8和GCC12&#xff0c;这里记录一下如何升级GCC版本&#xff0c;以及如何多版本并存。参考&#xff1a; CentOS升级gcc-知乎 Redhat7上安装Red Hat Developer Toolset并自由切换gcc和g的版本 Cent…

栈的生长方向不总是向下

据我了解&#xff0c;栈的生长方向向下&#xff0c;内存地址由高到低 测试 windows下&#xff1a; 符合上述情况 测试Linux下&#xff1a; 由此可见&#xff0c;栈在不同操作系统环境下&#xff0c;生长方向不总是向下

t检验(连续变量)和卡方检验(分类变量)

目录 情形 不同种类的萼片差异 数据类型查看&#xff1a; 差异分析&#xff1a; 不同萼片的种类差异 数据准备 二分类卡方检验 绘图 情形 &#xff1a;当有两列数据进行分析比较时&#xff0c;一列为连续变量&#xff0c;一列数据为分类变量。 rm(list ls()) libra…

uniapp 给小程序添加分享功能

在 Uni-app 中&#xff0c;要为小程序添加分享功能&#xff0c;你可以通过使用小程序的自定义分享组件或通过配置页面的分享信息来实现。下面我将分别介绍这两种方法。 方法一&#xff1a;使用小程序的自定义分享组件 在小程序中&#xff0c;你可以创建一个自定义的分享组件&…

Go语言中获取IP

简介 在net包中提供了获取所有网卡的ip&#xff0c;一般不会用127.0.0.1,::1这样的本地回环地址&#xff0c;可以过滤掉&#xff0c;如果想要获取当前真正在使用的地址&#xff0c;得通过net.Dail去连一下才知道 获取ip地址 func main() {fmt.Println(getIpv4())fmt.Println…

uniapp开发断小程序-如何判断小程序是在手机端还是pc端打开

官方说明 https://developers.weixin.qq.com/miniprogram/dev/devtools/pc-dev.html 小程序如何判断是 PC 平台&#xff1f; 通过 getSystemInfo 官方接口&#xff08;platform 是 windows&#xff09; 通过 UA&#xff08;PC UA 包含 MiniProgramEnv/Windows&#xff09; …

智能交通收费RFID读写器在不停车收费(ETC)系统中的应用

随着公路收费规模的不断扩大&#xff0c;传统的人工收费效率低下&#xff0c;收费没有监督&#xff0c;导致票款流失严重甚至还有车辆非法逃票。为了解决这些问题&#xff0c;引入了RFID等多种技术的新型的收费系统-不停车收费(ETC)系统应运而生。 电子不停车收费系统(ETC)系统…

JavaScript 中整数的安全范围

JavaScript 是一种广泛使用的编程语言&#xff0c;许多开发人员使用它来构建网页和应用程序。在 JavaScript 中&#xff0c;整数是一种常见的数据类型&#xff0c;但是对于整数的安全范围可能并不清楚。本文将探讨 JavaScript 中整数的安全范围是多少&#xff0c;并提供相应的代…

电商平台API接口的作用到底是什么?重要性又是什么?具体接入方式?

电商平台API接口的重要性及其作用主要体现在以下几个方面&#xff1a; 数据支持&#xff1a;电商平台拥有大量的商品信息、用户信息、交易信息等大数据资产&#xff0c;而API接口提供访问这些数据的途径&#xff0c;使得其他软件、应用、网站等可以利用这些数据提供更丰富的功…

设计模式篇---外观模式

文章目录 概念结构实例总结 概念 外观模式&#xff1a;为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用。 外观模式引入了一个新的外观类&#xff0c;它为多个业务类的调用提供了一个统一的入口。主要优点…

18张值得收藏的高清卫星影像

这里分享的18张高清卫星影像&#xff0c;由吉林一号卫星拍摄。 原图来自长光卫星嘉宾在直播中分享的PPT演示文档。 18张高清卫星影像 吉林一号高分04A星&#xff0c;于2022年05月21日拍摄的北京紫禁城高清卫星影像。 北京紫禁城 云南昆明滇池国际会展中心高清卫星影像&…

永洪BI安装字体教程

操作系统缺少中文字体造成部分字体显示不全 字体下载链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;0opj 安装命令: 创建文件夹&#xff0c;并放入字体文件 # mkdir /usr/share/fonts/Chinese 建立字体索引信息&#xff0c;更新字体缓存 # cd /usr/share/fonts/C…

jQuery【回到顶部、Swiper轮播图、立即执行函数、链式调用、参数重载、jQuery扩展】(六)-全面详解(学习总结---从入门到深化)

目录 回到顶部 Swiper轮播图 jQuery源码_立即执行函数 jQuery源码_链式调用 jQuery源码_参数重载 jQuery扩展 回到顶部 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compati…

如何去阅读源码,我总结了18条心法

那么到底该如何去阅读源码呢&#xff1f;这里我总结了18条心法&#xff0c;助你修炼神功 学好JDK 身为一个Javaer&#xff0c;不论要不要阅读开源项目源码&#xff0c;都要学好JDK相关的技术。 所有的Java类开源项目&#xff0c;本质上其实就是利用JDK已有的类库和关键字实现…

这13个不经意却很不卫生的行为,很多人都没意识到

这13个不经意却很不卫生的行为&#xff0c;很多人都没意识到 北京崇文中方中医医院名医馆 2023-11-11 17:01 发表于北京 我们在生活中不经意间做出的一些动作&#xff0c;或者日常养成的一些行为习惯&#xff0c;正在悄悄伤害着我们的身体健康。可惜的是很多人都不知道这一点…

了解UniApp常用方法

UniApp 是一个跨平台的应用开发框架&#xff0c;为开发者提供了丰富的原生 API 封装和扩展能力&#xff0c;以便于快速构建应用。在 UniApp 中&#xff0c;有许多常用的方法可供开发者使用&#xff0c;以下是对部分常用方法进行的总结和介绍。 页面生命周期方法 页面生命周期方…

archery修改为不能自提自审核上线SQL

目录 背景修改代码效果参考 背景 我和同事都可以提交上线SQL&#xff0c;但是不能自己提交的SQL自己去审核通过。目前的情况是可以自提自审。 修改代码 找到/opt/archery/sql/utils/workflow_audit.py文件 ...省略...# 判断用户当前是否是可审核staticmethoddef can_revie…

VMware Workstation系列:Windows10 优化VMware虚拟机运行速度总结(单台、多台-ESXI)

Windows10 优化VMware虚拟机运行速度总结 一. 单台或两台同时运行前言&#xff1a;优化方法环境&#xff1a; 1、清除多余快照2、清理磁盘。3、虚拟机全局设置5、设置“优先级”6、设置“设备”7、编辑虚拟机设置8、分配合适的内存和CPU 二. 多台并行背景&#xff1a;一. 下载1…

【书籍篇】Git 学习指南(三)版本库与分支

Git 学习指南&#xff08;三&#xff09;版本库与分支 五. 版本库5.1 一种简单而高效的存储系统5.2 存储目录&#xff1a;Blob与Tree5.3 相同数据只存储一次5.4 压缩相似内容5.5 不同文件散列值相同的情况5.6 提交对象5.7 提交历史中的对象宠用5.8 重命名、移动与复制 六. 分支…

golang学习笔记——切片

切片是数组或另一个切片之上的数据结构。 我们将源数组或切片称为基础数组。 通过切片&#xff0c;可访问整个基础数组&#xff0c;也可仅访问部分元素。 切片只有 3 个组件&#xff1a; 指向基础数组中第一个可访问元素的指针。 此元素不一定是数组的第一个元素 array[0]。切…