在Springboot项目中使用Quartz执行定时任务

所使用的jar包

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

使用默认单机模式。单机模式中,Job 和Trigger是存放在内存中Map,通过源码可以看出 quartz-2.3.0.sources.jar!/org/quartz/simpl/RAMJobStore.java

    protected HashMap<JobKey, JobWrapper> jobsByKey = new HashMap<JobKey, JobWrapper>(1000);protected HashMap<TriggerKey, TriggerWrapper> triggersByKey = new HashMap<TriggerKey, TriggerWrapper>(1000);protected HashMap<String, HashMap<JobKey, JobWrapper>> jobsByGroup = new HashMap<String, HashMap<JobKey, JobWrapper>>(25);protected HashMap<String, HashMap<TriggerKey, TriggerWrapper>> triggersByGroup = new HashMap<String, HashMap<TriggerKey, TriggerWrapper>>(25);protected TreeSet<TriggerWrapper> timeTriggers = new TreeSet<TriggerWrapper>(new TriggerWrapperComparator());protected HashMap<String, Calendar> calendarsByName = new HashMap<String, Calendar>(25);protected Map<JobKey, List<TriggerWrapper>> triggersByJob = new HashMap<JobKey, List<TriggerWrapper>>(1000);protected final Object lock = new Object();protected HashSet<String> pausedTriggerGroups = new HashSet<String>();protected HashSet<String> pausedJobGroups = new HashSet<String>();protected HashSet<JobKey> blockedJobs = new HashSet<JobKey>();

官网支持集群是把这些数据存放在mysql, 也有人改成使用redis存放这些数据

结合Springboot

注意此处Job要扩展QuartzJobBean, 只有这样才能使用@Autowired进来的其它service实例,否则要显式地new 一个相应service的实例

@Slf4j
@Component
@DisallowConcurrentExecution
public class MyJob extends QuartzJobBean {@AutowiredApplicationService applicationService;@Overrideprotected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {log.info("触发MyJob=========");applicationService.doSomething();Trigger trigger = jobExecutionContext.getTrigger();log.info("触发MyJob==========the trigger time : {}, 当前时间: {}",trigger.getStartTime(), new Date());}
}

设置Schedule

public interface QuartzService {void startSchedule ();void deployMySchedule (Myparams params) throws SchedulerException, ParseException;}

定义trigger并设置Schedule


@Slf4j
@Service
public class QuartzServiceImpl implements QuartzService {private final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.ENGLISH);private final String myJobName = "MyJobName";private final String QUARTZ_JOB_GROUP_SUFFIX = "Group";@Autowiredprivate Scheduler scheduler;@Overridepublic void deployMySchedule (MyParams params) throws SchedulerException, ParseException {if (checkMyJobExists(params)) {log.warn("已存在{}的任务", params.getJobName());updateMyJobTrigger(params);} else {log.info("不存在{}的任务, 添加任务", params.getJobName());arrangeNewMyJobSchedule(params);}}@Overridepublic void startSchedule ()  {try {scheduler.start();} catch (SchedulerException e) {log.error("Quartz 启动Schedule 出现异常 ==== ", e);}}/*** {*     "myJobName": "my.customized.job.name",*     "triggerTime": "2023-09-21 23:23:23"* }* @param params* @throws SchedulerException*/private void arrangeNewMyJobSchedule (MyParams params) throws SchedulerException, ParseException {String jobName = params.getMyJobName();String jobGroup = params.getMyJobName()+QUARTZ_JOB_GROUP_SUFFIX;String triggerTime = params.getTriggerTime();// TODO change triggerTime to Date()Date date = formatter.parse(triggerTime);log.info("{} 添加定时任务", params.getMyJobName());JobKey theJobKey = jobKey(jobName, jobGroup);JobDetail job = JobBuilder.newJob(MyJob.class).usingJobData("myJobName", params.getMyJobName()).withIdentity(theJobKey).build();// Simple trigger without repeating// withMisfireHandlingInstructionNextWithRemainingCount()// Does nothing, misfired execution is ignored and there is no next execution.// Use this instruction when you want to completely discard the misfired execution.// Example scenario: the trigger was suppose to start recording of a program in TV.// There is no point of starting recording when the trigger misfired and is already 2 hours late.// Discarded but job not removedTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey(jobName, jobGroup)).startAt(date).withSchedule(SimpleScheduleBuilder.simpleSchedule().withMisfireHandlingInstructionNextWithRemainingCount()).build();// 使用触发器调度任务的执行scheduler.scheduleJob(job, trigger);log.info("{} 设置任务触发时间为: {}, 配置触发器", params.getMyJobName(), triggerTime);log.info("schedule: scheduleName {}, scheduleInstanceId {} ", scheduler.getSchedulerName(),scheduler.getSchedulerInstanceId());}private void updateMyJobTrigger (MyParams params) throws SchedulerException, ParseException {String jobName = params.getMyJobName();String jobGroup = params.getMyJobName()+"Group";String triggerTime = params.getTriggerTime();updateJobTrigger(jobName, jobGroup, triggerTime);}private boolean checkMyJobExists (MyParams params) throws SchedulerException {String jobName = params.getMyJobName();String jobGroup = params.getMyJobName()+QUARTZ_JOB_GROUP_SUFFIX;JobKey jobKey = new JobKey(jobName, jobGroup);return scheduler.checkExists(jobKey);}private void updateJobTrigger (String jobName, String jobGroup, String triggerTime) throws ParseException {// TODO change triggerTime to Date()Date date = formatter.parse(triggerTime);try {TriggerKey triggerKey = triggerKey(jobName, jobGroup);SimpleTrigger oldTrigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);// Simple trigger without repeating// withMisfireHandlingInstructionNextWithRemainingCount()// 如果给的时间小于当前时间, 只重新配置触发器, 并不触发, 同时 jobdetail 也没有删除Trigger newTrigger = oldTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(simpleSchedule().withMisfireHandlingInstructionNextWithRemainingCount()).startAt(date).build();// 重启触发器scheduler.rescheduleJob(oldTrigger.getKey(), newTrigger);log.info("Job {} 任务触发时间更新为: {}, 重新配置触发器", jobName, triggerTime);} catch (SchedulerException e) {e.printStackTrace();}}
}

在项目启动时加载schedule

@Slf4j
@Component
public class MyQuartzScheduleStart {@AutowiredQuartzService quartzService;@PostConstructpublic void init() {log.info("Quartz 调度任务开始 =====");quartzService.startSchedule();}
}

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

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

相关文章

设计模式—装饰模式

与其明天开始&#xff0c;不如现在行动&#xff01; 文章目录 装饰模式—穿衣服&#x1f48e;总结 装饰模式—穿衣服 装饰模式&#xff08;Decorator&#xff09;可以动态的给对象添加一些额外的职责。 Component是定义一个对象接口&#xff0c;可以给这些对象动态地添加职责。…

C语言 typedef 和 #define 区别

typedef 和 #define 区别 typedef 仅限于数据类型&#xff0c;而不能是表达式或具体的值 #define 发生在预处理&#xff0c;typedef 发生在编译阶段 使用 typedef 给 函数指针类型 取别名 //语法&#xff1a; typedef int (*FuncPtr)(int, int);#include <stdio.h>typed…

Flutter ios 使用ListView 。滚动时 AppBar 改变颜色问题

在Ios 中 列表滚动条向下滚动一段距离后 会导致 AppBar 颜色改变 可以给 AppBar 或者 AppBarTheme。 scrolledUnderElevation: 0.0 属性 全局&#xff1a; MaterialApp(theme: ThemeData(appBarTheme: AppBarTheme(scrolledUnderElevation: 0.0)) ) 局部&#xff1a; App…

代码随想录算法训练营第二十天 |654.最大二叉树 、 617.合并二叉树 、700.二叉搜索树中的搜索 、 98.验证二叉搜索树

今天学习内容&#xff1a;654.最大二叉树 、 617.合并二叉树 、700.二叉搜索树中的搜索 、 98.验证二叉搜索树 讲解&#xff1a;代码随想录 654.最大二叉树 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 最大二叉树的构建过程如上&#xff0c;图…

STM32----HAL库函数

1.STM32系统框架 1.1 Cortex-M内核&芯片 1.2 F1系统框架 4个主动单元4个被动单元 AHB&#xff1a;高级高性能总线 APH&#xff1a;高级外围总线 其中 1 为 主动单元 &#xff0c; 2为被动单元 总线时钟频率&…

低代码开发平台的优势及应用场景分析

文章目录 低代码是什么&#xff1f;低代码起源低代码分类低代码的能力低代码的需求市场需要专业开发者需要数字化转型需要 低代码的趋势如何快速入门低代码开发低代码应用领域 低代码是什么&#xff1f; 低代码&#xff08;Low-code&#xff09;是著名研究机构Forrester于2014…

充电器如何测试?有哪些测试参数?用电源模块自动化测试系统测试需要哪些步骤?

充电器测试参数 1. 输入、输出电压测试 通过万用表或者其它精密测试设备测量充电器的输入、输出电压测试&#xff0c;检测输入、输出电压是否在规定范围内&#xff0c;以免造成设备损坏。 2. 输入、输出电流测试 测试充电器的输入、输出电流&#xff0c;确保其符合设计要求&…

C 标准库 - <string.h>

1 C 标准库 - <string.h> 简介 string .h 头文件定义了一个变量类型、一个宏和各种操作字符数组的函数。 1.1 库变量 下面是头文件 string.h 中定义的变量类型&#xff1a; 序号 变量 描述 1 size_t 这是无符号整数类型&#xff0c;它是 sizeof 关键字的结果。1.…

【AIGC重塑教育】AI大模型驱动的教育变革与实践

文章目录 &#x1f354;现状&#x1f6f8;解决方法✨为什么要使用ai&#x1f386;彩蛋 &#x1f354;现状 AI正迅猛地改变着我们的生活。根据高盛发布的一份报告&#xff0c;AI有可能取代3亿个全职工作岗位&#xff0c;影响全球18%的工作岗位。在欧美&#xff0c;或许四分之一…

数据库系统概论——复习资料

目录 一、概论 &#xff08;一&#xff09;数据库系统概述 &#xff08;二&#xff09;数据模型 &#xff08;三&#xff09;数据库系统的三级模式结构 &#xff08;四&#xff09;数据库系统的组成 二、关系数据库 &#xff08;一&#xff09;关系数据结构及形式化定义…

配电室综合监测系统

配电室综合监测系统是一种集成了自动化、智能化等技术手段的电力监控系统。它通过对配电室内的电力设备进行实时监控、数据分析和处理&#xff0c;能够提高电力设备的安全性和效率&#xff0c;及时发现并解决电力故障和潜在问题&#xff0c;保证电力系统的稳定运行。 该系统通常…

秒搜全网闲鱼商品!一键实现商品详情关键词搜索的酷炫电商API接口!

在如今的电商时代&#xff0c;商品搜索已经成为一个非常重要的功能。当用户在电商平台上浏览商品时&#xff0c;如果能够快速而准确地搜索到自己感兴趣的商品&#xff0c;无疑会提升用户的购物体验&#xff0c;进而增加平台的销售额。联讯数据将介绍一款名为“闲鱼商品秒搜API”…

创意产业集群与现代商业:共同探索新的商业模式

随着全球经济的快速发展和科技的日新月异&#xff0c;创意产业作为一种新兴的产业形态&#xff0c;逐渐受到人们的关注和重视。创意产业集群作为创意产业发展的重要组织形式&#xff0c;对于推动产业升级、提升经济竞争力具有重要意义。而传统商业作为历史悠久的商业形态&#…

10天玩转Python第10天:python unittest框架 全面详解与代码示例

目录 1.unittest 组成2.断言3.参数化4.测试报告 今日内容 unittest 框架的组成 TestLoaderFixture 断言跳过(某些用例由于某些原因不想执行)参数化测试报告 ​​​​ 1.unittest 组成 TestLoader (测试加载) TestLoader (测试加载), 作用和 TestSuite 的作用是一样的, 对 T…

亚信安慧AntDB数据库助力智慧高速建设

随着新型智慧交通业务的迅速发展&#xff0c;各地高速公路在管控、收费和监测方面的数据管理变得至关重要。智慧公路信息化建设已成为高速公路建设的核心。AntDB数据库在某省级客户中发挥关键作用&#xff0c;帮助构建协同共享、高效的统一智慧管理平台&#xff0c;为高速公路的…

内网BUG管理系统本地部署并结合内网穿透实现异地远程访问

文章目录 前言1. 本地安装配置BUG管理系统2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射本地服务3. 测试公网远程访问4. 配置固定二级子域名4.1 保留一个二级子域名5.1 配置二级子域名6. 使用固定二级子域名远程 前言 BUG管理软件,作为软件测试工程师的必备工具之一。在…

app上架-.您的应用在首次打开或运行中,未见使用权限对应的相关功能或服务时,提前向用户弹窗申请开启【已安装应用列表】权限,不符合华为应用市场审核标准。

上架提示 您的应用在首次打开或运行中&#xff0c;未见使用权限对应的相关功能或服务时&#xff0c;提前向用户弹窗申请开启【已安装应用列表】权限&#xff0c;不符合华为应用市场审核标准。 测试步骤&#xff1a;首次打开APP&#xff0c;在首页页面&#xff0c;非服务所必须…

实验4.1 静态路由的配置

实验4.1 静态路由的配置 一、任务描述二、任务分析三、具体要求四、实验拓扑五、任务实施1.设置交换机和路由器的基本配置。2.使用display ip interface brief命令查看接口配置信息。3.配置静态路由&#xff0c;实现全网互通。 六、任务验收七、任务小结 一、任务描述 某公司刚…

了解Java中的内存模型

目录 1、Java中的内存模型是什么 2、Java内存模型与操作系统内存模型的关系 3、Java内存模型是如何保证线程间的顺序性的 4、Java中的锁是如何保证线程安全的 5、多线程环境下如何保证数据一致性 1、Java中的内存模型是什么 在执行程序时&#xff0c;计算机的数据是存放在…

Linux常用网络指令

网络参数设定使用的指令 手动/自动设定与启动/关闭 IP 参数&#xff1a;ifconfig, ifup, ifdown ifconfig ifconfig常用于修改网络配置以及查看网络参数的指令 [rootwww ~]# ifconfig {interface} {up|down} < 观察与启动接口 [rootwww ~]# ifconfig interface {options…