【开发篇】十四、SpringBoot整合Quartz实现定时任务

文章目录

  • 1、关于定时任务
  • 2、Java原生实现
  • 3、相关名词
  • 4、SpringBoot整合Quartz
  • 5、Quartz的通用配置
  • 6、关于QuartzJobBean
  • 7、关于调度器Scheduler的绑定
  • 8、Quartz持久化

1、关于定时任务

定时任务在实际开发中使用场景很多,比如:

  • 年度报告
  • 各种统计报告
  • 某个同步任务

而定时任务的实现技术,业界流行的有:

  • Quartz
  • Spring Task

2、Java原生实现

demo代码如下:TimerTask是一个抽象类,new它的对象要实现方法,而它里面的run方法,应该能想到的是多线程也有个run,而定时任务也确实是这个run,到时间了以后就去开一个异步线程来执行任务。(TimerTask实现了Runnable接口)

import java.util.Timer;
import java.util.TimerTask;public class TaskTest{public static void main(String[] args){Timer timer = new Timer();TimerTask task = new TimerTask(){@Overridepublic void run(){System.out.println("task...");}}timer.schedule(task,0,2000);  //传入要执行的任务,0即从现在开始,2000即每隔两秒执行一次}
}

简单执行下,效果为每两秒输出以下task…

在这里插入图片描述

以上为原生Java的实现,在此基础上,市面上出现了更加完善和规范的落地技术Quartz,于是,Spring整合了Quartz,后来,Spring又推出了自己的Spring Task

3、相关名词

  • 工作(Job):用于定义具体执行的工作
  • 工作明细(JobDetail):用于描述定时工作相关的信息
  • 触发器(Trigger):用于描述触发工作的规则,通常使用cron表达式定义调度规则
  • 调度器(Scheduler):描述了工作明细与触发器的对应关系

其中,Job被JobDetail绑定,JobDetail又被Trigger绑定。

4、SpringBoot整合Quartz

导入Quartz起步依赖坐标:

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

继承QuartzJobBean,定义具体要执行的任务:

public class QuartzTaskBean extends QuartzJobBean {@Override    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {        //...这里写定时任务的逻辑代码System.out.println("quartz job run... ");    }
}

定义工作明细与触发器,并绑定对应关系:

@Configuration
public class QuartzConfig {    @Bean    public JobDetail printJobDetail(){        return JobBuilder.newJob(QuartzTaskBean.class) //传入上面的Job类,实现绑定到JobDetail.storeDurably()  //持久化,storeDurably()方法是用来持久化的,即Job创建完以后若当时没有使用,是否要持久化一下先存起来.build();}    @Bean    public Trigger printJobTrigger() {        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/3 * * * * ?");       return TriggerBuilder.newTrigger().forJob(printJobDetail())  //绑定JobDetail.withSchedule(cronScheduleBuilder).build();    }
}

整合完成,重启服务看下效果:

在这里插入图片描述

5、Quartz的通用配置

以上整合中,不用加任何配置,采用默认配置就完成了定时任务。但还可以在服务的yml配置文件中对Quartz进行更详细的配置。(可选)

spring:# Quartz 的配置,对应 QuartzProperties 配置类quartz:job-store-type: memory # Job 存储器类型。默认为 memory 表示内存,可选 jdbc 使用数据库。auto-startup: true # Quartz 是否自动启动startup-delay: 0 # 延迟 N 秒启动wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 trueoverwrite-existing-jobs: false # 是否覆盖已有 Job 的配置properties: # 添加 Quartz Scheduler 附加属性org:quartz:threadPool:threadCount: 25 # 线程池大小。默认为 10 。threadPriority: 5 # 线程优先级class: org.quartz.simpl.SimpleThreadPool # 线程池类型
#    jdbc: # 这里暂时不说明,使用 JDBC 的 JobStore 的时候,才需要配置

这些yaml配置自然有对应的实体类去读取和接收,这个实体类就是QuartzProperties搭配@ConfigurationProperties注解:

在这里插入图片描述

6、关于QuartzJobBean

QuartzJobBean类的源码:它实现了Job,并且定义了公用的execute方法

public abstract class QuartzJobBean implements Job {/*** This implementation applies the passed-in job data map as bean property* values, and delegates to {@code executeInternal} afterwards.* @see #executeInternal*/@Overridepublic final void execute(JobExecutionContext context) throws JobExecutionException {try {// 将当前对象包装为BeanWrapperBeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);// 设置属性MutablePropertyValues pvs = new MutablePropertyValues();pvs.addPropertyValues(context.getScheduler().getContext());pvs.addPropertyValues(context.getMergedJobDataMap());bw.setPropertyValues(pvs, true);}catch (SchedulerException ex) {throw new JobExecutionException(ex);}// 子类实现该方法executeInternal(context);}/*** Execute the actual job. The job data map will already have been* applied as bean property values by execute. The contract is* exactly the same as for the standard Quartz execute method.* @see #execute*/protected abstract void executeInternal(JobExecutionContext context) throws JobExecutionException;}

因此,创建Job的时候,可以继承QuartzJobBean类,也可直接实现Job接口,但继承QuartzJobBean并实现executeInternal方法,当然效率最高

7、关于调度器Scheduler的绑定

Scheduler绑定有两种方式,一种是使用bena的自动配置,一种是Scheduler手动配置。上面整合时,采用的是自动配置的方式,即定义两个Bean以及它们之间的关系,然后交给Spring容器管理。这里再补充一下手动配置的方式:实现Spring的ApplicationRuunner接口,注入Quartz的Scheduler对象,调用scheduleJob方法完成手动绑定

@Component
public class QuartzJob implements ApplicationRunner {@Resourceprivate Scheduler scheduler;@Overridepublic void run(ApplicationArguments args) throws Exception {//创建JobDetail对象JobDetail jobDetail = JobBuilder.newJob(QuartzTaskBean.class).storeDurably().build();// 简单的调度计划的构造器SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5) // 频率.repeatForever(); // 次数// 创建任务触发器Trigger trigger = TriggerBuilder.newTrigger().forJob(jobDetail).withSchedule(scheduleBuilder).startNow() //立即执行一次任務.build();// 手动将触发器与任务绑定到调度器内scheduler.scheduleJob(jobDetail, trigger);}
}

注意,这个类要注册成一个Bean,记得放在被Spring容器能扫描到的目录下。此外,上面没有用Cron表达式的调度器,用的简单的调度计划,调这个类提供的方法来描述你的执行规则就行。

在这里插入图片描述

8、Quartz持久化

Quartz持久化配置提供了两种存储器:RAMJobStore和JDBCJobStore,就是内存和硬盘:默认是内存形式维护任务信息,意味着服务重启了任务就从头再来,之前的执行数据等就全没了

存储方式优点缺点
RAMJobStore不要外部数据库,配置容易,运行速度快因为调度程序信息是存储在被分配给 JVM 的内存里面,所以,当应用程序停止运行时,所有调度信息将被丢失。另外因为存储到JVM内存里面,所以可以存储多少个 Job 和 Trigger 将会受到限制
JDBCJobStore支持集群,因为所有的任务信息都会保存到数据库中,可以控制事物,还有就是如果应用服务器关闭或者重启,任务信息都不会丢失,并且可以恢复因服务器关闭或者重启而导致执行失败的任务运行速度的快慢取决与连接数据库的快慢

下面实现持久化到MySQL,首先创建Quartz数据库,脚本在:

org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar!\org\quartz\impl\jdbcjobstore\tables_mysql_innodb.sql

在这里插入图片描述

这里有各种数据库类型的SQL脚本,执行完MySQL后查看表:

mysql> use quartz;
Database changed
mysql> show tables;
+--------------------------+
| Tables_in_quartz         |
+--------------------------+
| qrtz_blob_triggers       |## blog类型存储triggers
| qrtz_calendars           |## 以blog类型存储Calendar信息
| qrtz_cron_triggers       |## 存储cron trigger信息
| qrtz_fired_triggers      |## 存储已触发的trigger相关信息
| qrtz_job_details         |## 存储每一个已配置的job details
| qrtz_locks               |## 存储悲观锁的信息
| qrtz_paused_trigger_grps |## 存储已暂停的trigger组信息
| qrtz_scheduler_state     |## 存储Scheduler状态信息
| qrtz_simple_triggers     |## 存储simple trigger信息
| qrtz_simprop_triggers    |## 存储其他几种trigger信息
| qrtz_triggers            |## 存储已配置的trigger信息
+--------------------------+

加MySQL驱动以及JDBC的依赖坐标(看技术选型,采用MySQL驱动+MyBatis的不用加,MyBatis起步依赖下面包含Jdbc Starter)

<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency><!--看当前项目的已有依赖,很多封装JDBC的框架starter包含jdbc-starter-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency><!--数据源自己选吧,我用的druid,一般接手的项目这些肯定都有了-->

修改application.yml:

# 旧的数据源配置,用的druid
spring:datasource:druid:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/test_quartz?serverTimezone=GMT%2B8username: rootpassword: root123# quartz持久化的关键配置quartz:job-store-type: jdbc # 使用数据库存储scheduler-name: testScheduler # 相同 Scheduler 名字的节点,形成一个 Quartz 集群wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 truejdbc:initialize-schema: never # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。可以选择always,never,embedded,第一次也可偷懒让框架去创建表

重启服务,可以看到持久化成功:

在这里插入图片描述

除了以上关键配置外,集群、线程池等Quartz Scheduler 附加属性相关配置可参考以下这个COPY的比较全的配置文件:

spring:datasource:druid:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/test_quartz?serverTimezone=GMT%2B8username: rootpassword: root123quartz:job-store-type: jdbc # 使用数据库存储scheduler-name: hyhScheduler # 相同 Scheduler 名字的节点,形成一个 Quartz 集群wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 truejdbc:initialize-schema: never # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。可以选择always,never,embedded,第一次也可偷懒让框架去创建表properties:org:quartz:# JobStore 相关配置jobStore:dataSource: quartzDataSource # 使用的数据源class: org.quartz.impl.jdbcjobstore.JobStoreTX # JobStore 实现类driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegatetablePrefix: QRTZ_ # Quartz 表前缀isClustered: true # 是集群模式clusterCheckinInterval: 1000useProperties: false# 线程池相关配置threadPool:threadCount: 25 # 线程池大小。默认为 10 。threadPriority: 5 # 线程优先级class: org.quartz.simpl.SimpleThreadPool # 线程池类型

配置中有一个scheduler-name字段,看上面Quartz的库里的表,所有的表中都含有一个SCHED_NAME字段,对应配置的这个scheduler-name,相同 Scheduler-name的节点,形成一个 Quartz 集群。

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

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

相关文章

【小程序 - 加强】自定义组件、使用npm包、全局数据共享、分包_05

目录 一、自定义组件 1. 组件的创建与引用 1.1 创建组件 1.2 引用组件 1.2.1 局部引用组件 1.2.2 全局引用组件 1.2.3 全局引用 VS 局部引用 1.2.4 组件和页面的区别 2. 样式 2.1 组件样式隔离 2.2 组件样式隔离的注意点 2.3 修改组件的样式隔离选项 2.4 styleIso…

C++(List)

本节目标&#xff1a; 1.list介绍及使用 2.list深度剖析及模拟实现 3.list和vector对比 1.list介绍及使用 1.1list介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list的底层是双向链表结构&#xff0c;…

内网综合扫描工具-fscan的安装和使用

简介 一款内网综合扫描工具&#xff0c;方便一键自动化、全方位漏扫扫描。 支持主机存活探测、端口扫描、常见服务的爆破、ms17010、redis批量写公钥、计划任务反弹shell、读取win网卡信息、web指纹识别、web漏洞扫描、netbios探测、域控识别等功能。相当强大&#xff01;&…

国庆10.04

服务器 代码 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTcpServer> //服务器头文件 #include<QTcpSocket> //客户端头文件 #include<QList> //链表容器 #include<QMessag…

OpenCV(Python)的二值化示例

# -*-coding:utf-8-*- # src&#xff1a; 输入图&#xff0c;只能输入单通道图像&#xff0c;通常来说为灰度图 # - dst&#xff1a; 输出图 # - thresh&#xff1a; 阈值 # - maxval&#xff1a; 当像素值超过了阈值&#xff08;或者小于阈值&#xff0c;根据type来决定&#…

【重拾C语言】二、顺序程序设计(基本符号、数据、语句、表达式、顺序控制结构、数据类型、输入/输出操作)

目录 前言 二、顺序程序设计 2.1 求绿化带面积——简单程序 2.2基本符号&#xff1a; 2.2.1 字符集 可视字符 不可视字符 2.2.2 C特定符 关键字 分隔符 运算符 2.2.3 标识符 2.2.4 间隔符 2.2.5 注释 2.3 数据 2.3.1 字面常量&#xff08;Literal Constants&am…

扫雷小游戏(简单详细)(内附完整代码)

设计总体思路 实现游戏可以一直玩&#xff0c;先打印棋盘&#xff0c;玩家和电脑下棋&#xff0c;最后分出胜负。 如果编写较大的程序&#xff0c;我们可以分不同模块 例如这个扫雷&#xff0c;我们可以创建三个文件 分别为&#xff1a; game.h 函数的声明game.c 函数的…

MySQL数据库基础回顾与复习

MySQL数据库 一、原理定义概念 定义 数据库(Database)是按照数据结构来组织、存储和管理数据的建立在计算机存储设备上的仓库 数据库是长期储存在计算机内、有组织的、可共享的数据集合 分类&#xff1a; &#xff08;1&#xff09;非结构化数据&#xff1a; 数据相对来讲没…

微软输入法如何打勾和箭头的符号

文章目录 一、打 “√” 符号二、打 “←” 和 “→” 符号 一、打 “√” 符号 选中 “表情包” 图标 选中 “Ω” 符号后&#xff0c;下拉找到 “√” 即可。 微软输入法打 “ ”这个符号直接输入拼音“cha”就行。 二、打 “←” 和 “→” 符号 拼音直接打 “zuo” 或 “…

苹果ios系统IPA包企业签名手机下载应用可以有几种方式可以下载到手机?

一、App Store签名&#xff1a;这是最常见和推荐的苹果签名方式。用户可以通过苹果的官方应用商店App Store下载并安装经过苹果审核的应用程序。这种签名方式确保了应用程序的安全性和可靠性&#xff0c;因为App Store对应用进行了严格的审核和验证。 二、企业签名&#xff1a;…

【Kafka专题】Kafka集群架构设计原理详解

目录 前言前置知识课程内容一、Kafka的Zookeeper元数据梳理1.1 zookeeper整体数据1.2 Controller Broker选举机制1.3 Leader Partition选举机制1.4 Leader Partition自动平衡机制*1.5 Partition故障恢复机制1.6 HW一致性保障-Epoch更新机制1.7 总结 学习总结感谢 前言 Kafka的…

【VUE复习·9】v-for 基础用法(循环渲染也叫列表渲染)

总览 1.v-for 都能循环什么 2.用法 一、v-for 都能遍历什么 能循环的东西包括&#xff1a;数组、对象、字符串&#xff08;和java里面的3个引用数据类型一样&#xff09;、纯粹循环数量&#xff08;少用&#xff09; 二、用法 1.用法1&#xff1a;简单循环&#xff08;遍历…

扩散模型diffusion model 代码解读

代码来自这里 使用pytorch轻松实现简单扩散模型diffusion model&#xff08;附可跑通全部代码&#xff09; - 知乎 1.作者首先自己定义了一个数据集&#xff0c;也就是一堆散点&#xff0c;组成的S。 2.这些都是预先设置好的参数&#xff0c;也就是利用这些来做learning的提示…

【OLSR路由协议】链路状态路由(OLSR)协议中选择多点中继节点算法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Flink--7、窗口(窗口的概念、分类、API、分配器、窗口函数)、触发器、移除器

星光下的赶路人star的个人主页 内心的平静始于不再让他人掌控你的感情 文章目录 0、前言1、窗口&#xff08;Window&#xff09;1.1 窗口的概念1.2 窗口的分类1.3 窗口API概览1.4 窗口分配器&#xff08;Window Assigner&#xff09;1.4.1 时间窗口1.4.2 计数窗口 1.5 窗口函数…

【Linux基础】Linux云服务器(腾讯云、阿里云、华为云)环境部署 | 安装远程XShell | 基本账号管理(超详细教程)

&#x1f449; 系列专栏&#xff1a;【LLinux基础】 &#x1f648; 个人主页&#xff1a;sunnyll 目录 一、前言 二、 Linux环境安装 &#x1f4a6; Linux 环境的搭建方式 &#x1f4a6;如何购买云服务器 三、 安装远程控制XShell &#x1f4a6;下载 XShell &#x1f4…

[linux] SFTP文件传输基本命令 --- xshell 直接上传文件

2.sftp - 上传文件&#xff1a;如果上传/下载的是文件夹, 在put/get命令后加上-r参数即可。 上传文件&#xff1a; 把本地服务器的/www/wwwroot目录下面的study.log文件上传到远程服务器的/www/server目录下。 sftp> lcd /www/wwwroot sftp> put study.log /www/server…

c++中的动态内存管理

目录 1.内存分布 2.c语言动态内存管理 3.c动态内存管理 4.operator new 与operator delete 函数 5.定位new 6.malloc/free 与 new/delete 的区别 1.内存分布 首先我们需要了解一下数据在内存中的分布&#xff0c;请看以下代码&#xff1a; int globalVar 1; static in…

SNAP与Sen2Cor下载与安装

SNAP软件下载与安装 一、下载地址 首先进入网站 找到DOWNLOAD下载页&#xff0c; 安装完成后&#xff0c;界面如下 还需要再装一个Sen2cor下载好之后&#xff0c;解压到用户文件夹下 然后打开L2A_Process.bat文件 打开CMD&#xff0c;输入 cd C:\Users\lenovo\AppData\L…

C++:stl:stack、queue、priority_queue介绍及模拟实现和容量适配器deque介绍

本文主要介绍c中stl的栈、队列和优先级队列并对其模拟实现&#xff0c;对deque进行一定介绍并在栈和队列的模拟实现中使用。 目录 一、stack的介绍和使用 1.stack的介绍 2.stack的使用 3.stack的模拟实现 二、queue的介绍和使用 1.queue的介绍 2.queue的使用 3.queue的…