SpringBoot(二)集成 Quartz:2.5.4

news2025/1/11 17:12:18

Quartz是一个广泛使用的开源任务调度框架,用于在Java应用程序中执行定时任务和周期性任务。它提供了强大的调度功能,允许您计划、管理和执行各种任务,从简单的任务到复杂的任务。

以下是Quartz的一些关键特点和功能:

  • 灵活的调度器:Quartz提供了一个高度可配置的调度器,允许您根据不同的时间表执行任务,包括固定的时间、每日、每周、每月、每秒等。您可以设置任务执行的时间和频率。
  • 多任务支持:Quartz支持同时管理和执行多个任务。您可以定义多个作业和触发器,并将它们添加到调度器中。
  • 集群和分布式调度:Quartz支持集群模式,可以在多台机器上协调任务的执行。这使得Quartz非常适合大规模和分布式应用,以确保任务的高可用性和负载均衡。
  • 持久化:Quartz可以将任务和调度信息持久化到数据库中,以便在应用程序重启时不会丢失任务信息。这对于可靠性和数据保持非常重要。
  • 错过任务处理:Quartz可以配置在任务错过执行时如何处理,例如,是否立即执行、延迟执行或丢弃任务。
  • 监听器:Quartz提供了各种监听器,可以用来监视任务的执行,以及在任务执行前后执行自定义操作。
  • 多种作业类型:Quartz支持不同类型的作业,包括无状态作业(Stateless Job)和有状态作业(Stateful
    Job)。这允许您选择最适合您需求的作业类型。
  • 插件机制:Quartz具有灵活的插件机制,可以扩展其功能。您可以创建自定义插件,以满足特定需求。
  • 丰富的API:Quartz提供了丰富的Java API,使任务调度的配置和管理非常方便。

依赖

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

配置

spring.quartz.job-store-type=jdbc
# The first boot uses ALWAYS
spring.quartz.jdbc.initialize-schema=never
spring.quartz.auto-startup=true
spring.quartz.startup-delay=5s
spring.quartz.overwrite-existing-jobs=true
spring.quartz.properties.org.quartz.scheduler.instanceName=ClusterQuartz
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
spring.quartz.properties.org.quartz.jobStore.class=org.springframework.scheduling.quartz.LocalDataSourceJobStore
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
spring.quartz.properties.org.quartz.jobStore.isClustered=true
spring.quartz.properties.org.quartz.jobStore.acquireTriggersWithinLock=true
spring.quartz.properties.org.quartz.jobStore.misfireThreshold=12000
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=5000
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.org.quartz.threadPool.threadCount=1
spring.quartz.properties.org.quartz.threadPool.threadPriority=5
spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true


job


import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.stereotype.Component;

/**
 * @author Wang
 */
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Slf4j
@Component
public class DealerJob implements Job {

    @Override
    public void execute(JobExecutionContext context) {
        log.info("start Quartz job name: {}", context.getJobDetail().getKey().getName());
        DealerImportFacade dealerImportFacade = SpringUtil.getBean(DealerImportFacade.class);

        log.info(" start import US dealer data ");
        RequestContext.current().set(RequestContextCons.REGION, DataSourceEnum.US.toString().toLowerCase());
        try {
//            dealerImportFacade.importUsDealerData();
            log.info(" end import US dealer data ");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}

controller


import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

/**
 * @author Wang
 */
@RequiredArgsConstructor
@Slf4j
@RestController
@RequestMapping("/schedule/job")
public class ScheduleJobController {

    final ScheduleJobService scheduleJobService;
    final QuartzHelper quartzHelper;

    @PostMapping
    public AjaxRespData<ScheduleJobVO> addJob(@Valid @RequestBody AddScheduleJobDTO scheduleJobDTO) {
        ScheduleJobEntity scheduleJobEntity = BeanConvertUtils.convert(scheduleJobDTO, ScheduleJobEntity.class);
        scheduleJobEntity.init();
        scheduleJobEntity.setStatus(EnumScheduleJobStatus.RUN);
        ScheduleJobData data = scheduleJobService.save(scheduleJobEntity);
        quartzHelper.scheduleJob(data);
        return AjaxRespData.success(BeanConvertUtils.convert(data, ScheduleJobVO.class));
    }

    @DeleteMapping("/{jobId}")
    public AjaxRespData<Void> removeJob(@PathVariable("jobId") String jobId) {
        ScheduleJobEntity scheduleJobEntity = scheduleJobService.checkExist(jobId, EnumError.E30001);
        scheduleJobService.remove(jobId);
        quartzHelper.remove(scheduleJobEntity);
        return AjaxRespData.success();
    }

    @PutMapping("/{jobId}")
    public AjaxRespData<ScheduleJobVO> updateJob(@PathVariable String jobId, @Valid @RequestBody AddScheduleJobDTO scheduleJobDTO) {
        ScheduleJobEntity scheduleJobEntity = BeanConvertUtils.convert(scheduleJobDTO, ScheduleJobEntity.class);
        scheduleJobEntity.setId(jobId);
        ScheduleJobData data = scheduleJobService.update(scheduleJobEntity);
        quartzHelper.scheduleJob(data);
        return AjaxRespData.success(BeanConvertUtils.convert(data, ScheduleJobVO.class));
    }

    @GetMapping("/{jobId}")
    public AjaxRespData<ScheduleJobVO> getJob(@PathVariable("jobId") String jobId) {
        ScheduleJobEntity scheduleJobEntity = scheduleJobService.checkExist(jobId, EnumError.E30001);
        return AjaxRespData.success(BeanConvertUtils.convert(scheduleJobEntity, ScheduleJobVO.class));
    }


    @PutMapping("/operate")
    public void operateJob(@Valid @RequestBody AddScheduleJobDTO scheduleJobDTO) {
        ScheduleJobEntity scheduleJobEntity = scheduleJobService.checkExist(scheduleJobDTO.getId(), EnumError.E30001);
        scheduleJobEntity.setStatus(scheduleJobDTO.getStatus());
        scheduleJobService.update(scheduleJobEntity);
        quartzHelper.operateJob(scheduleJobDTO.getStatus(), scheduleJobEntity);
    }

}

service


import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author Wang
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class ScheduleJobService extends BaseService<ScheduleJobEntity, ScheduleJobData> {

    final ScheduleJobRepository scheduleJobRepository;
    final QuartzHelper quartzHelper;

    @PostConstruct
    public void init(){
        log.info("init schedule job...");
        List<ScheduleJobEntity> jobs = this.getRepository().findAll();
        for (ScheduleJobEntity job : jobs) {
            quartzHelper.scheduleJob(job);
            quartzHelper.operateJob(EnumScheduleJobStatus.PAUSE, job);
            if (job.getStatus().equals(EnumScheduleJobStatus.RUN)) {
                quartzHelper.operateJob(EnumScheduleJobStatus.RUN, job);
            }
        }
        log.info("init schedule job completed...");
    }

    @Override
    public BaseRepository<ScheduleJobEntity> getRepository() {
        return scheduleJobRepository;
    }


}

helper


import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.stereotype.Component;

import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Objects;

/**
 * @author Wang
 */
@RequiredArgsConstructor
@Slf4j
@Component
public class QuartzHelper {

    final Scheduler scheduler;

    public void scheduleJob(ScheduleJobEntity jobInfo) {

        JobKey jobKey = JobKey.jobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
        try {
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (Objects.nonNull(jobDetail)){
                scheduler.deleteJob(jobKey);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

        JobDetail jobDetail = JobBuilder.newJob(getJobClass(jobInfo.getType()))
                .withIdentity(jobKey)
                .build();

        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(jobInfo.getTriggerName(), jobInfo.getTriggerGroup()).startNow()
                .withSchedule(CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression()))
                .build();

        try {
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            log.error(e.getMessage(), e);
        }
    }

    public void rescheduleJob(ScheduleJobEntity job) {

        TriggerKey triggerKey = new TriggerKey(job.getTriggerName(), job.getTriggerGroup());
        try {
            CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            CronTrigger newCronTrigger = cronTrigger.getTriggerBuilder()
                    .withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression()))
                    .build();

            scheduler.rescheduleJob(triggerKey, newCronTrigger);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

    public void remove(ScheduleJobEntity job) {
        TriggerKey triggerKey = new TriggerKey(job.getTriggerName(), job.getTriggerGroup());
        try {
            scheduler.pauseTrigger(triggerKey);
            scheduler.unscheduleJob(triggerKey);
            scheduler.deleteJob(JobKey.jobKey(job.getTriggerName(), job.getTriggerGroup()));
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

    public void unscheduleJob(ScheduleJobEntity job) {

        TriggerKey triggerKey = new TriggerKey(job.getTriggerName(), job.getTriggerGroup());
        try {
            scheduler.unscheduleJob(triggerKey);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

    public void operateJob(EnumScheduleJobStatus status, ScheduleJobEntity job) {
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        try {
            switch (status) {
                case RUN:
                    scheduler.resumeJob(jobKey);
                    break;
                case PAUSE:
                    scheduler.pauseJob(jobKey);
                    break;
                default:
                    throw new IllegalArgumentException();
            }
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

    public String nextTime(ScheduleJobEntity job) {
        TriggerKey triggerKey = new TriggerKey(job.getTriggerName(), job.getTriggerGroup());
        try {
            Trigger trigger = scheduler.getTrigger(triggerKey);
            Date nextFireTime = trigger.getNextFireTime();
            return DateUtil.format(nextFireTime, DateTimeFormatter.ISO_DATE_TIME);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

    private Class<? extends Job> getJobClass(EnumScheduleJobType type) {
        Class<? extends Job> clazz;
        switch (type) {
            case DEALER_IMPORT:
                clazz = DealerJob.class;
                break;
//            case SECONDARY_INVITING_EXPIRE:
//                clazz = MockDeviceReportJob.class;
//                break;
            default:
                throw new IllegalArgumentException();
        }
        return clazz;
    }
}

最终效果

实例1,8281
在这里插入图片描述
实例2,8282
在这里插入图片描述

踩坑

定时任务执行间隔,最低设置一分钟

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

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

相关文章

海外问卷调查是不是真的能赚钱?

海外问卷调查是不是真的能赚钱&#xff1f;我来告诉你&#xff0c;我在橙河网络这家公司干了两年半的问卷调查&#xff0c;可以明确地告诉你&#xff1a;海外问卷调查确实可以赚钱&#xff0c;真的&#xff01; 海外问卷调查这个项目&#xff0c;在国内已经存在了很长时间&…

KVM动态在线迁移实操笔录

环境介绍 一台NFS&#xff08;192.168.184.132&#xff09; 一台KVM-a&#xff08;192.168.184.133&#xff09; 一台KVM-b&#xff08;192.168.184.134&#xff09; NFS配置 [rootlocalhost ~]# setenforce 0 //关闭selinux [rootlocalhost ~]# service iptables stop [root…

电子元器件网络变压器(网络滤波器 ̖ 脉冲变压器)的EMI产生原因

Hqst华强盛&#xff08;盈盛电子&#xff09;导读&#xff1a;网络变压器&#xff08;网络滤波器 ̖ 脉冲变压器&#xff0c;以下称网络变压器&#xff09;在工作过程中会产生电磁场&#xff0c;这可能会导致电磁干扰&#xff08;EMI&#xff09;。EMI会影响设备的性能和可靠性…

基于Java的图书商城管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

基于Java的图书馆借阅管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

设计模式:模板模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

简介&#xff1a; 模板模式&#xff0c;它是一种行为型设计模式&#xff0c;它定义了一个操作中的算法的框架&#xff0c;将一些步骤延迟到子类中实现&#xff0c;使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 通俗地说&#xff0c;模板模式就是将某一行…

微信小程序数据交互------WXS的使用

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 越努力 &#xff0c;越幸运。 1.数据库连接 数据表结构&#xff1a; 数据测式&#xff1a; 2.后台配置 pom.xml <?xml version&quo…

重磅发布!RflySim Cloud 智能算法云仿真平台亮相,助力大规模集群算法高效训练

RflySim Cloud智能算法云仿真平台&#xff08;以下简称RflySim Cloud平台&#xff09;是由卓翼智能及飞思实验室为无人平台集群算法验证、大规模博弈对抗仿真、人工智能模型训练等前沿研究领域研发的平台。主要由环境仿真模块、物理效应计算模块、多智能体仿真模块、分布式网络…

Python安装使用graphviz经验,Format: “png“ not recognized

Graphviz 是一款由 AT&T Research 和 Lucent Bell 实验室开源的可视化图形工具&#xff0c;可以很方便的用来绘制结构化的图形网络&#xff0c;支持多种格式输出。Graphviz 输入是一个用 dot 语言编写的绘图脚本&#xff0c;通过对输入脚本的解析&#xff0c;分析出其中的点…

摆闸机的应用领域和性能特点

摆闸机是一种常用于门禁控制和人员管理的设备&#xff0c;它具有以下应用领域和性能特点&#xff1a; 应用领域&#xff1a; 门禁控制&#xff1a;摆闸机可以用于各种场合的门禁控制&#xff0c;如小区、写字楼、学校、医院等。人员管理&#xff1a;摆闸机可以用于管理进出人…

最优化:建模、算法与理论(最优性理论2

5.7 约束优化最优性理论应用实例 5.7.1 仿射空间的投影问题 考虑优化问题 min ⁡ x ∈ R n 1 2 ∣ ∣ x − y ∣ ∣ 2 2 , s . t . A x b \min_{x{\in}R^n}\frac{1}{2}||x-y||_2^2,\\ s.t.{\quad}Axb x∈Rnmin​21​∣∣x−y∣∣22​,s.t.Axb 其中 A ∈ R m n , b ∈ R m …

【软考-中级】系统集成项目管理工程师-人力资源管理历年案例

持续更新。。。。。。。。。。。。。。。 目录 2019 下 试题三(20分)背诵整理1. 冲突管理的6种方法2. 获取项目人力资源的依据 系列文章 2019 下 试题三(20分) 阅读下列说明&#xff0c;回答问题 1至问题 3&#xff0c;将解答填入答题纸的对应栏内     某公司承接了一个软件…

Java BigDecimal计算及转换

BigDecimal应用汇总 1、负数转正数 a.abs(); 相当于&#xff1a;绝对值2、加法 a.add(b)3、减法 a.subtract(b) 相当于&#xff1a;a-b4、乘法 a.multiply(b)5、除法 a.divide(b) 相当于&#xff1a;a/b6、处理小数 BigDecimal.setScale()方法用于格式化小数点 setScale…

C++ vector 的使用

CSDN的uu们&#xff0c;大家好。这里是C入门的第十七讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 构造函数 1.1 vector(size_t n, const T& val T()) 1.2 vector…

laravel框架介绍(一) 开发环境配置

一.编译及开发工具 PHPStudy是一个windows下的Apache/NgnixPHPMySQL的集成开发环境 优点: 便于安装, 部署方便服务器版本快速切换集成了很多实用的工具 ​​​​​​小皮面板(phpstudy) - 让天下没有难配的服务器环境&#xff01; 二.配置和工具 2.1&#xff0c;Apache安装与…

论坛介绍|COSCon'23 开源百宝箱(T)

众多开源爱好者翘首期盼的开源盛会&#xff1a;第八届中国开源年会&#xff08;COSCon23&#xff09;将于 10月28-29日在四川成都市高新区菁蓉汇举办。本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01;各位新老朋友们&#xff0c;欢迎到成都&a…

聊聊设计模式--简单工厂模式

简单工厂模式 ​ 前面也学了很多各种微服务架构的组件&#xff0c;包括后续的服务部署、代码管理、Docker等技术&#xff0c;那么作为后端人员&#xff0c;最重要的任务还是代码编写能力&#xff0c;如何让你的代码写的漂亮、易扩展&#xff0c;让别人一看赏心悦目&#xff0c…

PAM从入门到精通(十七)

接前一篇文章&#xff1a;PAM从入门到精通&#xff08;十六&#xff09; 本文参考&#xff1a; 《The Linux-PAM Application Developers Guide》 PAM 的应用开发和内部实现源码分析 先再来重温一下PAM系统架构&#xff1a; 更加形象的形式&#xff1a; 六、整体流程示例 2.…

【SpringBoot底层原理】SpringBoot底层原理实践(一)——手撕SpringBoot容器(幼儿园版)

Spring底层原理实践&#xff08;一&#xff09;——手撕Spring容器&#xff08;幼儿园版&#xff09; 0. 前言1. 依赖2. 注解3. Bean定义类4. 容器接口5. 配置类6. 测试Bean7. 启动类8. 容器实现类8.1 容器初始化8.2 获取Bean8.3 创建Bean 9. 测试 0. 前言 SpringBoot项目创建…