【Java】【SpringBoot】Quartz——动态任务调度

news/2025/3/29 2:40:24/文章来源:https://www.cnblogs.com/luyj00436/p/18790581

回顾:前面学习了quartz的基础使用:https://www.cnblogs.com/luyj00436/p/18781141
定时任务可能是按照预设的时间进行。可是实际中,我们肯定希望自由的进行任务生成、暂停、恢复、删除、更新等操作。

Quartz本身没有提供动态调度的功能,需要自己根据相关的API开发。

场景

  • 订单成功后自动发送短信通知
  • 每日推送的功能引发用户不满,不再定时推送
  • 每日下班前20分钟发送工作报表,遇节假日暂停发发送。

Scheduler调度器常用API

API 说明
scheduler.scheduleJob(jobDetail,trigger) 生成一个新的定时任务
scheduler.paseJob(jobKey) 暂停一个定时任务,参数JobKey代表任务的唯一标识
scheduler.resumeJob(jobKey) 恢复一个定时任务,参数jobKey代表任务的唯一性
scheduler.deleteJob(jobKey) 删除一个定时任务,参数jobKey代表任务的唯一标识
scheduler.rescheduleJob(triggerKey, trigger) 修改一个定时任务
scheduler.triggerJob(jobKey) 执行一次定时任务

步骤

新增任务实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class JobBean {/*** 任务名字*/private String jobName;/*** 任务类*/private String JobClass;/*** cron表达式*/private String cronExpression;
}

接下来的任务,我们选择根据cron表达式的方式调度。

配置类

@Configuration
public class QuartzConfig {/*** 配置任务调度对象* @return*/@Beanpublic Scheduler getScheduler() throws SchedulerException {Scheduler scheduler = new StdSchedulerFactory().getScheduler();// 设置任务 和触发器
//        scheduler.scheduleJob(jobDetail(),trigger());// 启动scheduler.start();return scheduler;}
}

接下来,我们新建任务调度的工具类,这样需要动态调度任务时,就可以调度它。

public class JobUtils {/*** 创建任务* @param scheduler 任务调度器* @param jobBean 任务Bean*/public  static void createJob(Scheduler scheduler, JobBean jobBean){JobDetail jobDetail = null;     // 任务Class<? extends Job> jobClass = null;Trigger trigger = null;         // 触发器try {// 获取任务jobClass = Class.forName(jobBean.getJobClass()).asSubclass(Job.class);jobDetail = JobBuilder.newJob(HelloQuartz.class).storeDurably().withIdentity(jobBean.getJobName()).usingJobData("count",1).build();// 获取触发器trigger = TriggerBuilder.newTrigger().withIdentity(jobBean.getJobName()).withSchedule(CronScheduleBuilder.cronSchedule(jobBean.getCronExpression())).build();scheduler.scheduleJob(jobDetail,trigger);} catch (SchedulerException e) {// 调度器异常throw new RuntimeException(e);} catch (ClassNotFoundException e) {// 类转换异常throw new RuntimeException(e);}}/*** 删除任务* @param scheduler 任务调度器* @param jobName 任务名称*/public  static void deleteJob(Scheduler scheduler,String jobName){JobKey  jobKey = JobKey.jobKey(jobName);try {scheduler.deleteJob(jobKey);} catch (SchedulerException e) {// 调度器异常throw new RuntimeException(e);}}/*** 暂停任务* @param scheduler 任务调度器* @param jobName 任务名称*/public  static void pauseJob(Scheduler scheduler,String jobName){JobKey  jobKey = JobKey.jobKey(jobName);try {scheduler.pauseJob(jobKey);} catch (SchedulerException e) {// 调度器异常throw new RuntimeException(e);}}/*** 恢复任务* @param scheduler* @param jobName*/public static void resumeJob(Scheduler scheduler,String jobName){JobKey  jobKey = JobKey.jobKey(jobName);try {scheduler.resumeJob(jobKey);} catch (SchedulerException e) {// 调度器异常throw new RuntimeException(e);}}/*** 调用一次接口* @param scheduler 任务调度器* @param jobName 任务名称*/public static  void runJobOnce(Scheduler scheduler,String jobName){JobKey  jobKey = JobKey.jobKey(jobName);try {scheduler.triggerJob(jobKey);} catch (SchedulerException e) {// 调度器异常throw new RuntimeException(e);}}/*** 修改任务* @param scheduler 任务调度器* @param jobName 任务名称* @param cronExpression cron表达式*/public static void modifyJob(Scheduler scheduler,String jobName,String cronExpression){try {// 通过唯一标识获取旧的触发器对象CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(TriggerKey.triggerKey(jobName));// 使用新cron表达式构建触发器CronTrigger newTrigger = oldTrigger.getTriggerBuilder().withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build();// 调度器更新任务的触发器scheduler.rescheduleJob(oldTrigger.getKey(),newTrigger);} catch (SchedulerException e) {throw new RuntimeException(e);}}
}

接下来,创建接口,用于测试。

@RestController("/quartz")
public class QuartzController {// 使用 @Autowired 注入 Scheduler@ResourceWprivate Scheduler scheduler;private String crontext = "0/5 * * * * ?";private String newCrontext  = "0/2 * * * * ?";private String jobName = "job1";@GetMapping(value = "/createJob")public String createJob() {if (scheduler == null) {return "Scheduler 未正确初始化,请检查配置";}JobBean jobBean = new JobBean(jobName, HelloQuartz.class.getName(), crontext);JobUtils.createJob(scheduler, jobBean);return "创建任务成功";}@GetMapping(value = "/deleteJob")public String deleteJob() {if (scheduler == null) {return "Scheduler 未正确初始化,请检查配置";}JobUtils.deleteJob(scheduler, jobName);return "删除任务成功";}@GetMapping(value = "/pauseJob")public String pauseJob() {if (scheduler == null) {return "Scheduler 未正确初始化,请检查配置";}JobUtils.pauseJob(scheduler, jobName);return "暂停任务成功";}@GetMapping(value = "/resumeJob")public String resumeJob() {if (scheduler == null) {return "Scheduler 未正确初始化,请检查配置";}JobUtils.resumeJob(scheduler, jobName);return "恢复任务成功";}@GetMapping(value = "/runJobOnce")public String runJobOnce() {if (scheduler == null) {return "Scheduler 未正确初始化,请检查配置";}JobUtils.runJobOnce(scheduler, jobName);return "执行一次任务成功";}@GetMapping(value = "/modifyJob")public String modifyJob() {if (scheduler == null) {return "Scheduler 未正确初始化,请检查配置";}JobUtils.modifyJob(scheduler, jobName, newCrontext);return "修改任务成功";}
}

方法名删除任务、暂停任务、恢复任务、执行一次任务、修改任务,需要执行一次以后才能完成。

问题

上述方法中,如果暂停后重启任务,会多次执行任务。
image

这里涉及到人misfire 保护机制。默认情况下,中断的任务,会在恢复时继续执行错过的任务。

如果,我们希望暂停时,恢复后忽略所有错误任务,可以在创建或修改任务的cron表达式cronSchedule是添加属性withMisfireHandlingInstructionDoNothing

// 使用新cron表达式构建触发器
CronTrigger newTrigger = oldTrigger.getTriggerBuilder().withSchedule(CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing()).build();

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

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

相关文章

GrapeCity Documents V8.0 新版本特性

GcExcel V8.0 新版本特性丰富,包括:数据导入方面,可从多种数据源(如自定义对象、DataTable 等)导入,为 IRange.ImportData (..) 新增重载;假设分析上,通过 IWorksheet.Scenarios 接口支持 “方案” 功能,可进行多种操作且受保护工作表也能编辑;数据透视表能绑定表格数…

如何寻找替代FTP传输文件的软件,解决文件传输难题?

FTP因其操作简单、客户端种类多、价格低廉(甚至免费)等优势,受到众多企业的青睐,在全世界范围内得到广泛的应用。但它也面临着一些安全和效率方面的挑战,因此企业都在寻找可平滑替代FTP传输文件的软件。有以下局限性: 1.安全性弱:明文传输,漏洞频发,容易遭到DOS攻击;…

20244205 《Python程序设计》实验一报告

课程:《Python程序设计》 班级: 2442 姓名: 高赫 学号:20244205 实验教师:王志强 实验日期:2025年3月24日 必修/选修: 公选课 1.实验内容 (1).熟悉Python开发环境; (2).练习Python运行、调试技能; (3).编写程序,练习变量和类型、字符串、对象、缩进和注释等; (4).编…

微积分的本质——导数.18790288

本篇为3b1b系列【微积分的本质】笔记 原视频:02-导数的悖论 | 03-用几何来求导 | 04-直观理解链式法则和乘积法则定义导数 这是一个随着时间变化,车辆行驶距离的坐标图在横轴的任何一个点\(t\)上,如果你去查看车的车速表,上面都有一个数字表示当前的车速,但这是如何计算的…

推荐8款 .NET 开源、免费、实用的 Windows 效率软件

前言 今天大姚给大家推荐8款基于 .NET 开源、免费、实用的 Windows 效率软件,开发工作提升利器,希望可以帮助到有需要的小伙伴。 DevToys DevToys是一个专门为开发者设计的Windows工具箱,完全支持离线运行,无需使用许多不真实的网站来处理你的数据,常用功能有:格式化(支…

解密prompt系列51. R1实验的一些细节讨论

DeepSeek R1出来后业界都在争相复现R1的效果,这一章我们介绍两个复现项目SimpleRL和LogicRL,还有研究模型推理能力的Cognitive Behaviour,项目在复现R1的同时还针对R1训练策略中的几个关键点进行了讨论和消融实验,包括DeepSeek R1出来后业界都在争相复现R1的效果,这一章我…

读DAMA数据管理知识体系指南30文件和内容治理

读DAMA数据管理知识体系指南30文件和内容治理1. 方法 1.1. 诉讼应诉手册1.1.1. 电子取证工作一般在发生诉讼的时候进行1.1.2. 指引应明确电子取证的目标环境,并评估当前环境和目标环境之间是否存在差距1.1.3. 应记载电子取证活动生命周期的业务流程,明确电子取证团队的角色和…

为什么springboot的jar可以直接启动

一、讲述 1.SpringBoot提供了一个插件spring-boot-maven-plugin用于把程序打包成一个可执行的jar包。 2.Spring Boot应用打包之后,生成一个Fat jar(jar包中包含jar),包含了应用依赖的jar包和Spring Boot loader相关的 类。 3.java -jar会去找jar中的manifest文件,在那里面找…

折腾笔记[17]-使用rust创建linux系统服务

使用rust内嵌配置文件, 创建新用户并创建linux的service服务;实现后台服务循环打印时间到`/tmp/log_file_service`. Use Rust to embed configuration files, create new users, and create service services for Systemd; Implement a backend service loop to print time to …

[PNPM] 其他包管理器

Yarn Yarn 这个包管理器是在 2016 的时候由 Facebook、Google、Exponent 以及 Tilde 团队共同开发推出的。当时 Yarn 的出现主要是为了解决 npm 在速度、安全性以及一致性方面的一些问题:安装速度确定性:项目A ---> 直接依赖: libraryX(1.0)-----> 间接依赖:librar…

Kioptrix Level_1

Kioptrix Level 1.1 靶场配置 导入靶场时先将vmx后缀文件中的带有ethernet0的配置行全部删除,再导入靶场,添加一个网络适配器即可 信息收集 查找目标主机ip ┌──(root㉿kali)-[~] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:84:b2:cc, IPv4: 192.168…