SpringBoot(二)集成 Quartz:2.5.4

news/2025/3/24 10:12:27/

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 {@Overridepublic 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;@PostMappingpublic 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;@PostConstructpublic 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...");}@Overridepublic 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.ppmy.cn/news/1167201.html

相关文章

支持录音的笔记APP,可将录音转化为文字的笔记软件

提及笔记APP工具&#xff0c;无外乎是电子笔记和手写笔记&#xff0c;现如今随着科技的不断发展&#xff0c;人们使用电子设备的频率是越来越多&#xff0c;在选择笔记APP时&#xff0c;大家不想再单纯的依靠手动输入文字记录&#xff0c;反而更多的是喜欢快捷的录音添加笔记的…

【微信小程序】后台数据交互于WX文件使用

目录 一、前期准备 1.1 数据库准备 1.2 后端数据获取接口编写 1.3 前端配置接口 1.4 封装微信的request请求 二、WXS文件的使用 2.1 WXS简介 2.2 WXS使用 三、后台数据交互完整代码 3.1 WXML 3.2 JS 3.3 WXSS 效果图 一、前期准备 1.1 数据库准备 创建数据库&…

数据结构——栈与队列

数据结构——栈与队列 文章目录 数据结构——栈与队列一、栈的定义二、队列的定义 一、栈的定义 栈&#xff08;Stack&#xff09;是一种具有特殊限制的线性数据结构&#xff0c;它只允许在表的一端进行插入和删除操作。这一端被称为栈顶&#xff08;Top&#xff09;&#xff…

在mysql8查询中使用ORDER BY结合LIMIT时,分页查询时出现后一页的数据重复前一页的部分数据。

这里写目录标题 问题描述&#xff1a;问题模拟&#xff1a;原因分析问题解释问题解决验证官方文档支持 问题描述&#xff1a; 在mysql8查询中使用ORDER BY结合LIMIT时&#xff0c;分页查询时出现后一页的数据重复前一页的部分数据。 问题模拟&#xff1a; 表table_lock_test&…

21天打卡进阶Python基础操作

python21天打卡day3-python数据类型 #int a2 print(a) print(type(a)) #float a2.2 print(a) print(type(a)) #string anihao print(a) print(type(a)) #list a[1,2,3,4] print(a) print(a[0]) print(type(a)) #元组 a(1,2) print(a) print(type(a)) #字典dict a{name:yangyal,…

怎么恢复移走的u盘数据?可以尝试这三种方法

当意外移走U盘上的数据时&#xff0c;我们常常会感到焦虑和失望&#xff0c;特别是当这些数据对我们仍然重要时。不过&#xff0c;您不必完全放弃&#xff0c;因为本文将介绍一些方法&#xff0c;以帮助您恢复U盘上的重要数据。 图片来源于网络&#xff0c;如有侵权请告知 移走…

小程序之后台数据动态交互及WXS的使用 (5)

⭐⭐ 小程序专栏&#xff1a;小程序开发专栏 ⭐⭐ 个人主页&#xff1a;个人主页 目录 一.前言 二.后台数据交互 2.1 准备工作 2.1 前台首页数据连接&#xff1a; 三.WXS的使用 今天就分享到这啦&#xff01;&#xff01;&#xff01; 一.前言 本文章续前面的文章的前端界面…

基于YOLOv8的多目标检测与自动标注软件【python源码+PyqtUI界面+exe文件】【深度学习】

基本功能演示 摘要&#xff1a;YOLOv8是YOLO系列最新的版本&#xff0c;支持多种视觉任务。本文基于YOLOv8的基础模型实现了80种类别的目标检测&#xff0c;可以对图片进行批量自动标注&#xff0c;并将检测结果保存为YOLO格式便于后续进行其他任务训练。本文给出完整的Python实…