springboot集成quartz

news2024/11/28 0:41:00

文章目录

  • 前言
  • 一、Quartz是什么?
      • 难易程度
  • 二、核心思想
  • 三、使用步骤
    • 1.引入依赖
    • 2.创建相应类
  • 总结


前言

引用上一篇博客的说法 springboot整合xxl-job ,集群模式下,定时任务会造成很严重的事故,其次普通的任务也无法做到像xxl-job与Quartz 一样,及时启停,修改等;上一篇介绍了xxl-job,这篇搞一下Quartz,老牌分布式定时任务了;


一、Quartz是什么?

比较详细的Quartz文档

难易程度

Quartz 并没有给出明确的例子,但是文档详细,且任务的操作简单明了,步骤清晰,本身是可以脱离Spring-boot 单独工作的,而且可以更高度自定义话。需要自己摸搜整合,一般还需要自己维护数据库的表等,为了任务的添加做参数等;
xxl-job 官方提供了springboot以及普通项目集成demo,所以在集成方面,只要理解了它的思想xxl-job集成很快,数据库等都是现有的,导入即可;但是封装较深,尤其分为了服务端与客户端,无形增加了服务数量,且通信之间还有可能有通信信息丢失情况等;

二、核心思想

  1. Quartz 的调度中心是Scheduler,所以只要将任务交给它就行了
  2. 一个通用的任务是JobDetail,用来接受各种具体的任务逻辑
  3. CronTrigger 是JobDetail 的触发条件,所以Scheduler需要的是 JobDetail 任务和CronTrigger 任务触发器
  4. JobDetail既然是通用任务,用于接受任务,所以我们要定义一个自己的任务类(例如叫做QuartzJob),这个任务类需要实现 Job接口
  5. 这个任务类QuartzJob,要执行具体的任务,具体的任务,一般都是我们需要自己的一些方法,
    例如: 每天晚上12点执行一次清理数据库之前的数据; 一般我们会写一个这样的方法
    public class LogImpl implements LogService{
    	public void clear(){
    		logService.remove(new Date());
    	}
    }
    
    那么QuartzJob中其实就要执行LogImpl 这个类中的 clear()这个方法,这里通过反射执行;
    6. 因为我们一般都会在数据库中加入 LogImpl 这个类中的 clear()这个方法,然后交给Quartz执行,所以只能通过反射执行

三、使用步骤

1.引入依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

2.创建相应类

  1. QuartzUtil 此类作为操作job的工具类,这里的job与quartz中的 JobDetail一一对应 ,包括任务的增删改
public class QuartzUtil {

    /**
     * 将新增的任务放入quartz调度中心中执行
     *
     * @param sysJob 具体任务信息
     * @throws Exception 异常
     */
    @SneakyThrows
    public static void insertOrUpdateJob(SysJob sysJob) {
        // 获取调度器 Scheduler
        Scheduler scheduler = SchedulerStatic.getScheduler();
        Long jobId = sysJob.getJobId();
        String jobGroup = sysJob.getJobGroup();

        // 构造一个job
        JobKey jobKey = JobKey.jobKey(jobId.toString(), jobGroup);
        JobDetail jobDetail = JobBuilder
                .newJob(QuartzJob.class)
                .withIdentity(jobKey)
                .build();

        // 构造cron调度器
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(sysJob.getCronExpression());
        getMisfirePolicy(sysJob, cronScheduleBuilder);

        // 构造触发器 trigger
        TriggerKey triggerKey = TriggerKey.triggerKey(jobId.toString(), jobGroup);
        CronTrigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity(triggerKey)
                .withSchedule(cronScheduleBuilder)
                .build();

        // 放入job信息,为后续执行改任务的具体方法做铺垫(需要反射调用), 在execute中获取并应用
        jobDetail.getJobDataMap().put(QuartzEnum.jobKey, sysJob);
        // 判断该任务是否存在,修改任务,先删除然后添加
        if (scheduler.checkExists(jobKey)) {
            // 防止创建时存在数据问题 先移除,然后在执行创建操作
            scheduler.deleteJob(jobKey);
        }
        // 判断任务是否过期
        CronExpression cron = new CronExpression(sysJob.getCronExpression());
        Date nextValidTimeAfter = cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
        if (!ObjectUtils.isEmpty(nextValidTimeAfter)) {
            // 执行调度任务
            scheduler.scheduleJob(jobDetail, trigger);
        }
        // 暂停任务
        if (sysJob.getStatus().equals(QuartzEnum.PAUSE)) {
            scheduler.pauseJob(jobKey);
        }
    }


    /**
     * 根据计划执行错误策略,设置调度器
     *
     * @param sysJob              任务信息
     * @param cronScheduleBuilder cron调度器
     */
    private static void getMisfirePolicy(SysJob sysJob, CronScheduleBuilder cronScheduleBuilder) {
        switch (sysJob.getMisfirePolicy()) {
            case QuartzEnum.MISFIRE_DEFAULT:
                break;
            case QuartzEnum.MISFIRE_IGNORE_MISFIRES:
                cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();
                break;
            case QuartzEnum.MISFIRE_FIRE_AND_PROCEED:
                cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed();
                break;
            case QuartzEnum.MISFIRE_DO_NOTHING:
                cronScheduleBuilder.withMisfireHandlingInstructionDoNothing();
                break;
            default:
                throw new RuntimeException("The task misfire policy '" + sysJob.getMisfirePolicy() + "' cannot be used in cron schedule tasks");
        }
    }

    /**
     * 删除任务
     *
     * @param sysJob 具体任务信息(获取jobkey)
     */
    @SneakyThrows
    public static void deleteJob(SysJob sysJob) {
        // 获取调度器 Scheduler
        Scheduler scheduler = SchedulerStatic.getScheduler();
        scheduler.deleteJob(JobKey.jobKey(sysJob.getJobId().toString(), sysJob.getJobGroup()));
    }
}
  1. QuartzJob
    1. 此类作为所有任务的执行入口,其他要执行的具体逻辑应该注入spring,然后通过此 通过反射调用到具体任务执行类
    1. sysJob包含着要执行的具体逻辑类的信息,以及方法,参数等信息,此案例维护在数据库中
    1. 通过更改数据库数据,动态变更quartz中的任务
    1. 目前仅仅做了无参构造器的方法执行,后续补充
public class QuartzJob implements Job {

   @Override
   public void execute(JobExecutionContext context) throws JobExecutionException {
       // 获取任务执行参数
       SysJob sysJob = (SysJob) context.getJobDetail().getJobDataMap().get(QuartzEnum.jobKey);

       // invokeTarget 应该符合 类.方法名 例如 task.sout()
       String invokeTarget = sysJob.getInvokeTarget();
       String beanName = invokeTarget.split("\\.")[0];
       String temp = invokeTarget.split("\\.")[1];
       String methodName = temp.substring(0, temp.indexOf("("));

       Object bean = SpringUtil.getBean(beanName);
       Method method = null;
       try {
           method = bean.getClass().getMethod(methodName);
           method.invoke(bean);
       } catch (Exception e) {
           e.printStackTrace();
           throw new RuntimeException(e);
       }
   }
}
  1. SchedulerStatic 此类仅仅作为引入静态调度器的工具类
@Component
public class SchedulerStatic {

    private static Scheduler scheduler;

    @Autowired
    public SchedulerStatic(Scheduler scheduler) {
        SchedulerStatic.scheduler = scheduler;
    }

    public static Scheduler getScheduler() {
        return scheduler;
    }
}

  1. MyTask
    . 此类作为具体执行任务的示例类
  • 此类应该注入spring容器中,为了后去获取方便,且一般业务都需要查询数据,所以此类比较常见
  • 如果非bean,那么 {@link com.example.springbootquartz.quartz.QuartzJob}.中需要自己扩展获取目标类 利用Class.forName()
@Service("task")
public class MyTask {

    @Autowired
    SysJobService sysJobService;

    /**
     * 任务的具体执行逻辑写在此处,这里只做打印
     */
    public void sout() {
        List<SysJob> list = sysJobService.list();
        list.forEach(sysJob -> System.out.println(sysJob.toString()));
    }
}
  1. yml 配置文件
    集成了swagger mp mysql quartz等
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/quartz?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
    username: root
    password: root

  # 页面配置
  mvc:
    path match:
      matching-strategy: ant_path_matcher
server:
  port: 8889

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  1. 通过接口文档地址,操作任务,达到动态更改分布式任务的效果
  • 直接访问控制台打印的地址即可
    启动效果
  • 通过添加任务的详细信息,查看任务执行情况
    新增任务
    可以看到,已经开始执行任务了,0/2 * * * * ? 每两秒后执行一次
    执行的是打印
    具体任务

总结

基本实现了任务的动态添加
后续完善:

  • 有参数的具体任务调用,修改QuartzJob中的方法获取,参数获取等,但是依旧采用代理实现
  • 任务并发执行未处理,后续完善

项目地址: springboot-quartz

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

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

相关文章

文心一言 VS 讯飞星火 VS chatgpt (41)-- 算法导论5.4 5题

五、在大小为n的集合中&#xff0c;一个k字符串构成一个k排列的概率是多少?这个问题和生日悖论有什么关系? 文心一言&#xff1a; 在大小为n的集合中&#xff0c;一个k字符串构成一个k排列的概率是1/k!&#xff0c;这是由于排列的总数是k!&#xff0c;而每个字符串被选中的…

十大开源 ChatGPT 替代品:弥合对话式 AI 的差距

聊天机器人彻底改变了企业与客户互动的方式。由 OpenAI 开发的最先进的 GPT-4 是该领域的主导者。但是&#xff0c;它不是开源的&#xff0c;这限制了开发人员复制结果或开发自己的类似于 GPT-4 的聊天机器人。 为了填补这一空白&#xff0c;开源社区已经开始提供 GPT-4 的替代…

Qt6.5.1+WebRTC学习笔记(十二)环境搭建流媒体服务器(ubuntu22.04+SRS)

前言 若只是实现一对一通信&#xff0c;仅使用webrtc就足够了。但有时间需要进行多个人的直播会议&#xff0c;当人比较多时&#xff0c;建议使用一个流媒体服务器&#xff0c;笔者使用的是SRS。 这个开源项目资料比较全&#xff0c;笔者仅在此记录下搭建过程 一、准备 1.操…

移远通信率先完成多场5G NTN技术外场验证,为卫星物联网应用落地提速

近日&#xff0c;由中国电信卫星公司牵头&#xff0c;移远通信联合紫光展锐、鹏鹄物宇等行业上下游合作伙伴&#xff0c;针对现有蜂窝通信在信号覆盖盲区&#xff0c;信息监测数据无法实时回传等痛点问题&#xff0c;以领先行业的速度开展了一系列的5G NTN&#xff08;non-terr…

Unity入门7——物理系统之碰撞检测

一、刚体 Rigid Body ​ 刚体利用体积&#xff08;碰撞器 Collider&#xff09;进行碰撞计算&#xff0c;模拟真实的碰撞效果&#xff0c;产生力的作用 ​ 碰撞产生的必要条件&#xff1a; 两个物体都有碰撞器 Collider至少一个物体有刚体 Mass&#xff1a;质量 默认为千克&a…

postman自动化实战总结

Postman实战总结 简介 本次实战内容主要包括如下几点&#xff1a; l 背景介绍 l Postman使用&#xff0c;侧重于自动化实现&#xff0c;基础使用不做介绍 l 可视化Newman介绍 l 框架特色 l 实战中的坑 背景 随着国内软件技术的高速发展&#xff0c;越来越多的手工测试…

Qgis2threejs

three.js是JavaScript编写的一个开源的3D图形库&#xff0c;它可以用于创建各种各样的交互式3D应用程序和动画。该库提供了一系列的工具和功能&#xff0c;使得在Web浏览器中创建高质量的3D图形变得更加容易。 使用three.js&#xff0c;您可以轻松地创建3D场景&#xff0c;包括…

GoogleNet

Introduction 得益于深度学习的优势和更强大的卷积神经网络的出现&#xff0c;图像分类和目标检测的准确率发生了令人意想不到的进步。在2014年的ILSVRC比赛中&#xff0c;GoogLeNet取得了第一名的成绩&#xff0c;所用模型参数不足AlexNet&#xff08;2012年冠军&#xff09;…

基于Java医院住院管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

记录使用gswin64.exe合并多个pdf为一个pdf

目录 下载gs920w64.exe 安装 配置相关信息 验证是否安装配置成功 合并多个pdf文件 下载gs920w64.exe https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/tag/gs920 ​ 安装 正常安装&#xff0c;记住自己的安装目录&#xff1a; ​ 配置相关信息 安装…

限流与令牌桶

一、概述 令牌桶是一种常用的流量控制技术。令牌桶本身没有丢弃和优先级策略。 原理 1&#xff0e;令牌以一定的速率放入桶中。 2&#xff0e;每个令牌允许源发送一定数量的比特。 3&#xff0e;发送一个包&#xff0c;流量调节器就要从桶中删除与包大小相等的令牌数。 4…

跟着《代码随想录刷题》(六)—— 二叉树

6.1 二叉树的前、中、后序遍历 144.、二叉树的前序遍历&#xff08;中左右&#xff09; LeetCode&#xff1a;114、二叉树的前序遍历 &#xff08;1&#xff09;递归法 class Solution { public:void traversal(TreeNode* cur, vector<int>& vec) {if (cur N…

eslint + prettier如何搭配使用

简介 eslintprettier写代码爽到飞起&#xff0c;既规范了代码的格式&#xff0c;同时也让你的代码美观易读。本文介绍如何在项目中使用eslint搭配prettier来规范你的代码 1.eslint 和 prettier区别 先来回答一个问题&#xff0c;eslint和prettier这二者有啥区别&#xff0c;es…

【后端面经-数据库】MySQL的事务隔离级别简介

【后端面经-数据库】MySQL的事务隔离级别简介 0. 事务的概念1. 三类问题2. 事务隔离级别3. 操作指令4. 总结5. 参考博文 0. 事务的概念 事务指的是一连串的集中操作指令&#xff0c;一个事务的执行必须执行完所有的动作才能算作执行结束。事务具有四个特点&#xff0c;简记作A…

表示学习(Representation Learning) Part2--Auto-Encoders、VAEs、GANs

文章目录 Compression:Auto-EncodersCapture parameter distribution (variance): Variational Auto-Encoders原理介绍数学推导生成数据diffusion modelsPros&Cons Train using a second network: GANs 来自Manolis Kellis教授&#xff08;MIT计算生物学主任&#xff09;的…

spark_idea

spark_idea 3、打jar包运行2、code1、pom_xml0、创建数据、模型、预测表0、Windows配置scala环境 3、打jar包运行 ./bin/spark-submit \--class spark02 \--master spark://hadoop102:7077 \--deploy-mode client \/home/gpb/scala_spark2.jar打jar包、存储到虚拟机中 编写执行…

什么是布隆过滤器?如何解决高并发缓存穿透问题?

日常开发中&#xff0c;大家经常使用缓存&#xff0c;但是你知道大型的互联网公司面对高并发流量&#xff0c;要注意缓存穿透问题吗!!! 本文会介绍布隆过滤器&#xff0c;空间换时间&#xff0c;以较低的内存空间、高效解决这个问题。 本篇文章的目录&#xff1a; 1、性能不…

IMX6ULL裸机篇之SPI实验-ICM20608代码实现

一. SPI 实验 SPI实验&#xff1a;学习如何使用 I.MX6U 的 SPI 接口来驱动 ICM-20608&#xff0c;读取 ICM-20608 的六轴数据。 本文学习 SPI通信实验中&#xff0c;涉及从设备的 SPI代码编写。 之前学习了 SPI 主控芯片代码的编写&#xff0c;如下所示&#xff1a; IMX6ULL…

【ROS】RViz使用详解

1、安装 1.1 ROS1-RVIZ RVIZ的ROS1各个ubuntu版本中的安装命令 ubuntu14.04&#xff1a; sudo apt install ros-indigo-rvizubuntu16.04&#xff1a; sudo apt install ros-kinetic-rvizubuntu18.04&#xff1a; sudo apt install ros-melodic-rvizubuntu20.04&#xff1a…

Java厘米级高精准定位系统源码(支持UWB、蓝牙、WIFI定位)

高精准定位系统支持10厘米工业级高精准定位&#xff0c;同时支持UWB&#xff0c;蓝牙&#xff0c;WIFI定位。 ♦高精准定位系统首页为数据统计页面&#xff0c;统计的信息可以分为数量统计、区域告警人数统计、工牌使用量的统计、区域报警率统计以及告警消息的展示。 系统首页…