深入浅出,SpringBoot整合Quartz实现定时任务与Redis健康检测(一)
目录
前言
环境配置
Quartz
什么是Quartz?
应用场景
核心组件
Job
JobDetail
Trigger
CronTrigger
SimpleTrigger
Scheduler
任务存储
RAM
JDBC
导入依赖
定时任务
销量统计
Redis检测
使用
编辑
注意事项
前言
在悦享校园1.0中引入了Quartz框架实现了对于商家每日的销量统计功能,而目前项目已升级到SpringBoot版本,因此需要进行对应的代码进行调整。除此之外考虑到若Redis出现故障时或使用该项目不想要配置Redis时如何保证该项目正常启动呢?即当Redis出现故障时如何无缝切换到数据库查询数据而不是抛出错误信息?由于项目中整合Redis的客户端为Lettuce,因此可以考虑使定时任务实现对Redis服务的监测从而无感切换数据查询操作。
环境配置
JDK 1.8
Spring Boot 2.7.12
lettuce 6.1.10(包含在Spring-Boot-Starter-Data-Redis中)
Quartz 2.3.2
Quartz
什么是Quartz?
根据官方文档描述,Quartz 是一种功能丰富的,开放源码的作业调度库,可以在集成在任何的Java应用程序中,小到独立的应用程序,大到复杂的电子商务系统。 Quartz可以用来创建简单或复杂的日程安排执行几十,几百,甚至数以万计的作业数,作业被定义为标准的Java组件,可以通过编程使其执行。
应用场景
如文章开头所述,当我们需要统计店铺的每日销量或者每周销量时,可以通过一个定时任务来执行相应的操作。以及Redis由于长时间不使用时可能会造成客户端除此之外,也可以将Quartz使用到如定期发送消息通知,如获取每日天气进行邮件推送到指定客户等其它的操作。这些都可通过Quartz来实现。除此之外Quartz还能完成其它复杂的任务。
核心组件
Job
用于存放真正需要定时执行的任务逻辑
JobDetail
用于对任务信息的相关描述,如任务名称、任务分组等。需要注意的是,JobDetail中含有一个Key属性,该属性将通过传入的任务名称和分组名称构建Key,若参数为空时则通过UUID来构建,从而确保该Key是唯一的。因此相同的任务名称和组名会覆盖之前的任务,这一点是需要注意的。
使用JobDetail+Job方式的设计,可以避免在并发情况下,对同一个实例的访问问题。
可以通过JobDataMap将数据存储并将数据传给Job实例。
Trigger
Trigger即为触发器,用于指定将以何种方式执行定时任务,注意Trigger与JobDetail一一对应,即一个触发器只做用于一个定义任务上。以下为两种常用的触发器:
CronTrigger
其核心在于使用Cron表达式进行任务的构建,如下是一个表示每月最后一天执行任务的Cron表达式:
# 每月的最后1天0 0 L * * *说明:Linux* * * * *- - - - -| | | | || | | | +----- day of week (0 - 7) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat| | | +---------- month (1 - 12) OR jan,feb,mar,apr ...| | +--------------- day of month (1 - 31)| +-------------------- hour (0 - 23)+------------------------- minute (0 - 59)
鉴于网上关于Cron表达式的文章非常多,这里不做过多赘述。这里列举几个常用的Cron表达式:
(1)0/2 * * * * ? 表示每2秒 执行任务
(2)0 0/2 * * * ? 表示每2分钟 执行任务
(3)0 0 2 1 * ? 表示在每月的1日的凌晨2点调整任务
(4)0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
(5)0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
(5)0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
可以通过Crontab.guru - The cron schedule expression editor 网站来验证Cron表达式。
SimpleTrigger
相比于上述提到的Cron表达式,SimpleTrigger来构建一些指定间隔时间执行的任务更加容易,如每隔75s执行某个任务,则使用SimpleTrigger更佳。
Scheduler
任务调度器,它可以JobDetail与Trigger关联起来,通过任务调度器将启动任务的执行。一个任务调度器中可以包含多个关联的实例。
任务存储
Quartz提供了两种定时任务存储功能,一种为RAM,另一种为JDBC。
RAM
默认情况下Quartz会将任务数据存储到内存中,优点为任务读取速度快,简单易用。但缺点是随着服务重启会导致任务丢失。(本文采用该方式)
JDBC
Quartz提供了对定时任务持久化的功能,可以通过创建对应的数据表将定时任务持久化到数据库中,如此一来可以确保任务不会因为服务重启而丢失,可以更好的管理任务。缺点是需要额外的进行数据库表创建。本文采用默认的RAM方式存储,可以自行通过具体需求场景来选择。
导入依赖
由于本文项目使用了SpringBoot,因此导入如下依赖即可
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency>
定时任务
任务创建可以通过继承 QuartzJobBean 类并重写其excuteInternal方法,或实现 Job 接口的excute方法,从QuartzJobBean的源码可知,其实现了Job接口,因此以上的创建方式任选其一即可。
销量统计
销量统计任务类,此处仅使用日志打印体现,具体的业务逻辑可自行编写
@Slf4j
public class SellDailyJob extends QuartzJobBean {@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {log.info("这是每日销量统计定时任务。。。");}
}
执行规则配置类
@Configuration
public class SellDailyConfig{@Bean("sellDailyJob")public JobDetail jobDetail(){// 指定任务执行的类return JobBuilder.newJob(SellDailyJob.class)// 任务名称和分组名,不可重复.withIdentity("sellDailyJob", "group").withDescription("任务描述:内存方式运行").storeDurably().build();}@Bean("sellDailyTrigger")public Trigger trigger() {return TriggerBuilder.newTrigger()// 触发器名和分组名,不可重复.withIdentity("trigger", "group").forJob(jobDetail()).startNow()// 使用Cron表达式构建执行事件 每5s执行一次.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();}}
Redis检测
Redis健康检测定时任务类,构建方法同上
@Slf4j
public class RedisCheckJob extends QuartzJobBean {@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {log.info("这是Redis定时心跳任务");}
}
执行规则配置类
@Configuration
@Slf4j
public class RedisCheckConfig {// 指定生成的Bean实例对象名称@Bean("redisCheck")public JobDetail jobDetail() {return JobBuilder.newJob(RedisCheckJob.class)// 任务名和任务分组.withIdentity("RedisCheckJob", "group").withDescription("任务描述:内存方式运行").storeDurably().build();}@Bean("redisTrigger")public Trigger trigger() {return TriggerBuilder.newTrigger()// 触发器名称和分组.withIdentity("redisCheck", "group").forJob(jobDetail()).startNow()// 使用SimpleSchedule构建定时任务.withSchedule(SimpleScheduleBuilder.simpleSchedule()// 每隔10s执行任务.withIntervalInSeconds(10)// 永不过期.repeatForever()).build();}
}
使用
上个部分中分别使用CronTrigger和SimpleTrigger构建了两种定时任务,而根据SpringBoot官方文档中所示,当Quartz可用时,SchedulerFactoryBean会将Scheduler自动装配到容器中,因此在SpringBoot中使用@Configuration+@Bean注解构建定时任务后,无需显式创建Scheduler,SpringBoot会自动加载这些定时任务交由Scheduler调度。
因此配置完成后只需启动应用程序即可,执行结果如下所示。
注意事项
1.以上构建定时任务时需要创建任务类并在其中写入自定义的业务方法。并在配置类newJob中写入对应任务类。jobDetail和Trigger方法使用@Bean注解构建时,需要指定名称且不重复,否则其它配置类无法正常构建Bean实例。
2.jobDetail方法和trigger方法中的withIdentity应分别指定不同任务名和任务分组,需要保证其它配置类中以上两个属性之中至少有一个属性不同,否则同样将造成定时任务无法正常执行。(eg:A配置类中的任务名为work,分组名为group,B中配置与之相同则会导致A服务无法正常运行)
相关文章:

深入浅出,SpringBoot整合Quartz实现定时任务与Redis健康检测(一)
目录 前言 环境配置 Quartz 什么是Quartz? 应用场景 核心组件 Job JobDetail Trigger CronTrigger SimpleTrigger Scheduler 任务存储 RAM JDBC 导入依赖 定时任务 销量统计 Redis检测 使用 编辑 注意事项 前言 在悦享校园1.0中引入了Quart…...

Lucene-MergePolicy详解
简介 该文章基于业务需求背景,因场景需求进行参数调优,下文会尽可能针对段合并策略(SegmentMergePolicy)的全参数进行说明。 主要介绍TieredMergePolicy,它是Lucene4以后的默认段的合并策略,之前采用的合并…...
数据的加解密
文章目录 分类特点业务的使用补充 分类 对称加密算法非对称加密算法 特点 对称加密算法 : 加密效率高 !加密和解密都使用同一款密钥 但是有一个问题 : 密钥如何从服务端发给客户端? (假如你直接先将密钥发给对方,要是在过程中被黑客技术破解了,那后面的消息也就泄漏了) (后…...

【Spring】更简单的读取和存储对象
更简单的读取和存储对象 一. 存储 Bean 对象1. 前置工作:配置扫描路径2. 添加注解存储 Bean 对象Controller(控制器存储)Service(服务存储)Repository(仓库存储)Component(组件存储&…...

【LeetCode热题100】--108.将有序数组转换为二叉搜索树
108.将有序数组转换为二叉搜索树 给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。 二叉搜索树的中序遍历是升序…...

Redis学习笔记(下):持久化RDB、AOF+主从复制(薪火相传,反客为主,一主多从,哨兵模式)+Redis集群
十一、持久化RDB和AOF 持久化:将数据存入硬盘 11.1 RDB(Redis Database) RDB:在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。 备份…...

【智能家居项目】裸机版本——设备子系统(LED Display 风扇)
🐱作者:一只大喵咪1201 🐱专栏:《智能家居项目》 🔥格言:你只管努力,剩下的交给时间! 输入子系统中目前仅实现了按键输入,剩下的网络输入和标准输入在以后会逐步实现&am…...
[Linux]记录plasma-wayland下无法找到HDMI接口显示器的问题解决方案
内核:Linux 6.5.5-arch1-1 Plasma 版本:5.27.8 窗口系统:Wayland 1 问题 在前些时候置入了一块显示器,接口较多,有 HDMI 接口,type-C 接口。在 X11 中可以找到外接显示器,但是卡顿明显…...

【计算机网络】高级IO之select
文章目录 1. 什么是IO?什么是高效 IO? 2. IO的五种模型五种IO模型的概念理解同步IO与异步IO整体理解 3. 阻塞IO4. 非阻塞IOsetnonblock函数为什么非阻塞IO会读取错误?对错误码的进一步判断检测数据没有就绪时,返回做一些其他事情完整代码myt…...
如何设计一个高效的应用缓冲区【一个动态扩容的buffer类】
文章目录 前言一、为什么需要设计应用层缓冲区必须要有 output buffer目的问题output buffer的解决方案: 必须要有 input buffer总结 二、设计要点三、buffer设计思路基础函数关于iovec与readv readfd如何实现动态扩容 问题 前言 在上一个博客,我们介绍…...

图像处理初学者导引---OpenCV 方法演示项目
OpenCV 方法演示项目 项目地址:https://github.com/WangQvQ/opencv-tutorial 项目简介 这个开源项目是一个用于演示 OpenCV 方法的工具,旨在帮助初学者快速理解和掌握 OpenCV 图像处理技术。通过这个项目,你可以轻松地对图像进行各种处理&a…...

管道-匿名管道
一、管道介绍 管道(Pipe)是一种在UNIX和类UNIX系统中用于进程间通信的机制。它允许一个进程的输出直接成为另一个进程的输入,从而实现数据的流动。管道是一种轻量级的通信方式,用于协调不同进程的工作。 1. 创建和使用管道&#…...

【JavaEE基础学习打卡08】JSP之初次认识say hello!
目录 前言一、JSP技术初识1.动态页面2.JSP是什么3.JSP特点有哪些 二、JSP运行环境配置1.JDK安装2.Tomcat安装 三、编写JSP1.我的第一个JSP2.JSP执行过程3.在IDEA中开发JSP 总结 前言 📜 本系列教程适用于JavaWeb初学者、爱好者,小白白。我们的天赋并不高…...

使用序列到序列深度学习方法自动睡眠阶段评分
深度学习方法,用于使用单通道脑电图进行自动睡眠阶段评分。 def build_firstPart_model(input_var,keep_prob_0.5):# List to store the output of each CNNsoutput_conns []######### CNNs with small filter size at the first layer ########## Convolutionnetw…...

【算法】排序——选择排序和交换排序(快速排序)
主页点击直达:个人主页 我的小仓库:代码仓库 C语言偷着笑:C语言专栏 数据结构挨打小记:初阶数据结构专栏 Linux被操作记:Linux专栏 LeetCode刷题掉发记:LeetCode刷题 算法头疼记:算法专栏…...

Docker 容器监控 - Weave Scope
Author:rab 目录 前言一、环境二、部署三、监控3.1 容器监控 - 单 Host3.2 容器监控 - 多 Host 总结 前言 Docker 容器的监控方式有很多,如 cAdvisor、Prometheus 等。今天我们来看看其另一种监控方式 —— Weave Scope,此监控方法似乎用的人…...
Spring Boot集成redis集群拓扑动态刷新
项目场景: Spring Boot集成Redis集群,使用lettuce连接Cluster集群实例。 问题描述 redis其中一个节点挂了之后,springboot集成redis集群配置信息没有及时刷新,出现读取操作报错。 java.lang.IllegalArgumentException: Connec…...
COCI2022-2023#1 Neboderi
P9032 [COCI2022-2023#1] Neboderi 题目大意 有一个长度为 n n n的序列 h i h_i hi,你需要从中选择一个长度大于等于 k k k的子区间 [ l , r ] [l,r] [l,r],使得 g ( h l h l 1 ⋯ h r ) g\times (h_lh_{l1}\cdotsh_r) g(hlhl1⋯hr)最小&…...

由于找不到d3dx9_43.dll无法继续执行此代码怎么解决?全面解析d3dx9_43.dll
在使用计算机过程中,我们可能会遇到各种各样的问题。其中之一就是d3dx9_43.dll文件丢失的问题。这个问题通常会出现在运行某些应用程序或游戏时,导致程序无法正常启动或运行。那么,如何解决这个问题呢?小编将为您提供一些解决方案…...

Linux--网络编程-字节序
进程间的通信: 管道、消息队列、共享内存、信号、信号量。 特点:都依赖于linux内核。 缺陷:无法多机通信。 一、网络编程: 1、地址:基于网络,ip地址端口号。 端口号作用: 一台拥有ip地址的主机…...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...