本文侧重SpringBoot与Quartz的整合,Quartz的基本入门概念不清楚的小伙伴可以看看这篇文章:任务调度框架Quartz快速入门!

本篇要点

  • 介绍SpringBoot与Quartz单机版整合。
  • 介绍Quartz持久化存储。

SpringBoot与Quartz单机版快速整合

学习完非Spring环境下Quartz的使用,再来看SpringBoot你会感到更加自如,因为SpringBoot无非是利用它自动配置的特性,将一些重要的Bean自动配置到环境中,我们直接开箱即用,关于Quartz的自动配置定义在QuartzAutoConfiguration中。

引入依赖

主要是spring-boot-starter-quartz这个依赖,是SpringBoot与Quartz的整合。

        <!-- 实现对 Spring MVC 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!-- 实现对 Quartz 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

创建Job

为了演示两种Trigger及两种配置方式,我们创建两个不同的Job。

@Slf4j
public class FirstJob extends QuartzJobBean { @Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
String now = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
log.info("当前的时间: " + now);
}
} @Slf4j
public class SecondJob extends QuartzJobBean { @Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
String now = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
log.info("SecondJob执行, 当前的时间: " + now);
}
}

我们在创建Job的时候,可以实现Job接口,也可以继承QuartzJobBean。

QuartzJobBean实现了Job,并且定义了公用的execute方法,子类可以继承QuartzJobBean并实现executeInternal方法。

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
*/
@Override
public final void execute(JobExecutionContext context) throws JobExecutionException {
try {
// 将当前对象包装为BeanWrapper
BeanWrapper 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; }

调度器Scheduler绑定

Scheduler绑定有两种方式,一种是使用bena的自动配置,一种是Scheduler手动配置。

自动配置,这里演示SimpleScheduleBuilder

@Configuration
public class QuartzConfig { private static final String ID = "SUMMERDAY"; @Bean
public JobDetail jobDetail1() {
return JobBuilder.newJob(FirstJob.class)
.withIdentity(ID + " 01")
.storeDurably()
.build();
} @Bean
public Trigger trigger1() {
// 简单的调度计划的构造器
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5) // 频率
.repeatForever(); // 次数 return TriggerBuilder.newTrigger()
.forJob(jobDetail1())
.withIdentity(ID + " 01Trigger")
.withSchedule(scheduleBuilder)
.build();
}
}

手动配置,这里演示CronScheduleBuilder

@Component
public class JobInit implements ApplicationRunner { private static final String ID = "SUMMERDAY"; @Autowired
private Scheduler scheduler; @Override
public void run(ApplicationArguments args) throws Exception {
JobDetail jobDetail = JobBuilder.newJob(FirstJob.class)
.withIdentity(ID + " 01")
.storeDurably()
.build();
CronScheduleBuilder scheduleBuilder =
CronScheduleBuilder.cronSchedule("0/5 * * * * ? *");
// 创建任务触发器
Trigger trigger = TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withIdentity(ID + " 01Trigger")
.withSchedule(scheduleBuilder)
.startNow() //立即執行一次任務
.build();
// 手动将触发器与任务绑定到调度器内
scheduler.scheduleJob(jobDetail, trigger);
}
}

yml配置

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 ,建议设置为 true
overwrite-existing-jobs: false # 是否覆盖已有 Job 的配置
properties: # 添加 Quartz Scheduler 附加属性
org:
quartz:
threadPool:
threadCount: 25 # 线程池大小。默认为 10 。
threadPriority: 5 # 线程优先级
class: org.quartz.simpl.SimpleThreadPool # 线程池类型
# jdbc: # 这里暂时不说明,使用 JDBC 的 JobStore 的时候,才需要配置

SpringBoot自动配置中:spring.quartz对应的配置项定义在QuartzProperties中。

主启动类

@SpringBootApplication
public class DemoSpringBootApplication { public static void main(String[] args) {
SpringApplication.run(DemoSpringBootApplication.class, args);
}
}

测试

启动程序,FirstJob每5s执行一次,SecondJob每10s执行一次。

 [eduler_Worker-1] com.hyhwky.standalone.FirstJob           : FirstJob执行, 当前的时间: 2020-12-26 16:54:00
[eduler_Worker-2] com.hyhwky.standalone.SecondJob : SecondJob执行, 当前的时间: 2020-12-26 16:54:00
[eduler_Worker-3] com.hyhwky.standalone.FirstJob : FirstJob执行, 当前的时间: 2020-12-26 16:54:05
[eduler_Worker-4] com.hyhwky.standalone.SecondJob : SecondJob执行, 当前的时间: 2020-12-26 16:54:10
[eduler_Worker-5] com.hyhwky.standalone.FirstJob : FirstJob执行, 当前的时间: 2020-12-26 16:54:10
[eduler_Worker-6] com.hyhwky.standalone.FirstJob : FirstJob执行, 当前的时间: 2020-12-26 16:54:15
[eduler_Worker-7] com.hyhwky.standalone.SecondJob : SecondJob执行, 当前的时间: 2020-12-26 16:54:20

Quartz持久化配置

Quartz持久化配置提供了两种存储器:

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

创建数据库表

为了测试Quartz的持久化配置,我们事先在mysql中创建一个数据库quartz,并执行脚本,脚本藏在org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar!\org\quartz\impl\jdbcjobstore\tables_mysql_innodb.sql,jdbcjobstore中有支持许多种数据库的脚本,可以按需执行。

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信息
+--------------------------+

所有的表中都含有一个SCHED_NAME字段,对应我们配置的scheduler-name,相同 Scheduler-name的节点,形成一个 Quartz 集群。

引入mysql相关依赖

    <dependencies>
<!-- 实现对 Spring MVC 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 实现对 Quartz 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>

配置yml

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

配置数据源

@Configuration
public class DataSourceConfiguration { private static HikariDataSource createHikariDataSource(DataSourceProperties properties) {
// 创建 HikariDataSource 对象
HikariDataSource dataSource = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
// 设置线程池名
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
} /**
* 创建 quartz 数据源的配置对象
*/
@Primary
@Bean(name = "quartzDataSourceProperties")
@ConfigurationProperties(prefix = "spring.datasource.quartz")
// 读取 spring.datasource.quartz 配置到 DataSourceProperties 对象
public DataSourceProperties quartzDataSourceProperties() {
return new DataSourceProperties();
} /**
* 创建 quartz 数据源
*/
@Bean(name = "quartzDataSource")
@ConfigurationProperties(prefix = "spring.datasource.quartz.hikari")
@QuartzDataSource
public DataSource quartzDataSource() {
// 获得 DataSourceProperties 对象
DataSourceProperties properties = this.quartzDataSourceProperties();
// 创建 HikariDataSource 对象
return createHikariDataSource(properties);
} }

创建任务

@Component
public class JobInit implements ApplicationRunner { private static final String ID = "SUMMERDAY"; @Autowired
private Scheduler scheduler; @Override
public void run(ApplicationArguments args) throws Exception {
JobDetail jobDetail = JobBuilder.newJob(SecondJob.class)
.withIdentity(ID + " 02")
.storeDurably()
.build();
CronScheduleBuilder scheduleBuilder =
CronScheduleBuilder.cronSchedule("0/10 * * * * ? *");
// 创建任务触发器
Trigger trigger = TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withIdentity(ID + " 02Trigger")
.withSchedule(scheduleBuilder)
.startNow() //立即執行一次任務
.build();
Set<Trigger> set = new HashSet<>();
set.add(trigger);
// boolean replace 表示启动时对数据库中的quartz的任务进行覆盖。
scheduler.scheduleJob(jobDetail, set, true);
}
}

启动测试

启动测试之后,我们的quartz任务相关信息就已经成功存储到mysql中了。

mysql> select * from qrtz_simple_triggers;
+--------------+---------------------+---------------+--------------+-----------------+-----------------+
| SCHED_NAME | TRIGGER_NAME | TRIGGER_GROUP | REPEAT_COUNT | REPEAT_INTERVAL | TIMES_TRIGGERED |
+--------------+---------------------+---------------+--------------+-----------------+-----------------+
| hyhScheduler | SUMMERDAY 01Trigger | DEFAULT | -1 | 5000 | 812 |
+--------------+---------------------+---------------+--------------+-----------------+-----------------+
1 row in set (0.00 sec) mysql> select * from qrtz_cron_triggers;
+--------------+---------------------+---------------+------------------+---------------+
| SCHED_NAME | TRIGGER_NAME | TRIGGER_GROUP | CRON_EXPRESSION | TIME_ZONE_ID |
+--------------+---------------------+---------------+------------------+---------------+
| hyhScheduler | SUMMERDAY 02Trigger | DEFAULT | 0/10 * * * * ? * | Asia/Shanghai |
+--------------+---------------------+---------------+------------------+---------------+

源码下载

本文内容均为对优秀博客及官方文档总结而得,原文地址均已在文中参考阅读处标注。最后,文中的代码样例已经全部上传至Gitee:https://gitee.com/tqbx/springboot-samples-learn,另有其他SpringBoot的整合哦。

参考阅读

SpringBoot整合任务调度框架Quartz及持久化配置的更多相关文章

  1. Java任务调度框架Quartz入门

    Quartz[kwɔːts]:石英,其框架和名字一样简单朴素又不失魅力,在Java程序界,Quartz大名鼎鼎,很多Java应用几乎都集成或构建了一个定时任务调度系统,Quartz是一个定时任务调度框 ...

  2. 通过源码分析Java开源任务调度框架Quartz的主要流程

    通过源码分析Java开源任务调度框架Quartz的主要流程 从使用效果.调用链路跟踪.E-R图.循环调度逻辑几个方面分析Quartz. github项目地址: https://github.com/t ...

  3. [源码分析] 定时任务调度框架 Quartz 之 故障切换

    [源码分析] 定时任务调度框架 Quartz 之 故障切换 目录 [源码分析] 定时任务调度框架 Quartz 之 故障切换 0x00 摘要 0x01 基础概念 1.1 分布式 1.1.1 功能方面 ...

  4. 企业级任务调度框架Quartz(1) --企业应用中的任务调度介绍

    由于目前的工作内容为建行CLPM批处理业务的设计工作,所以很好的理解批处理所用的任务调度框架Quartz势在必行:为了能够更好的去服务于工作,也 为了提升自己,所以我学习了Quartz Job Sch ...

  5. 2流高手速成记(之三):SpringBoot整合mybatis/mybatis-plus实现数据持久化

    接上回 上一篇我们简单介绍了基于SpringBoot实现简单的Web开发,本节来看Web开发中必不可少的内容--数据持久化 先看项目结构: 1. 创建数据表 打开mysql,打开数据库 test (没 ...

  6. 企业级任务调度框架Quartz(8) 线程在Quartz里的意义(2)

    前序:      做为企业里的任务调度框架,出现同一时间点同时运行两个任务,或者两个任务因为开始的执行时间和执行时间的长短,很有可能出现任务并发执行的情况:因为Quartz的实现是采用java编程,那 ...

  7. SpringBoot整合日志框架LogBack

    日志可以记录我们应用程序的运行情况,我们可以通过日志信息去获取应用程序更多的信息.常用处理java日志的组件有:slf4j.log4j.logback.common-logging等.其中log4j是 ...

  8. Java任务调度框架Quartz教程

    一.什么是quartz作业调度? Quartz框架是一个全功能.开源的任务调度服务,可以集成几乎任何的java应用程序—从小的单片机系统到大型的电子商务系统.Quartz可以执行上千上万的任务调度. ...

  9. 任务调度框架Quartz原理简介

    [TOC] 第一章 Quartz 1.1 Quartz概念 Quartz是OpenSymphony开源组织的一个Java开源项目, 在2009被Terracotta收购.Quartz官网 1.2 Qu ...

随机推荐

  1. vue+element ctrl+s保存写法

    <el-input type="textarea" ref="inppp" v-model="values" placeholder= ...

  2. 基于gin的golang web开发:Gin技术拾遗

    本文是对前几篇文章的一些补充,主要包含两部分:单元测试和实际项目中使用路由的小问题. 拾遗1:单元测试 Golang单元测试要求代码文件以_test结尾,单元测试方法以Test开头,参数为*testi ...

  3. Hadoop完全分布式模式安装部署

    在Linux上搭建Hadoop系列:1.Hadoop环境搭建流程图2.搭建Hadoop单机模式3.搭建Hadoop伪分布式模式4.搭建Hadoop完全分布式模式 注:此教程皆是以范例讲述的,当然你可以 ...

  4. Python中的文档字符串作用

    文档字符串是使用一对三个单引号 ''' 或者一对三个双引号 """来包围且没有赋值给变量的一段文字说明(如果是单行且本身不含引号,也可以是单引号和双引号), 它在代码执行 ...

  5. 第二十六章、containers容器类部件QToolBox工具箱详解

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.概述 容器部件就是可以在部件内放置其他部件的部件,在Qt Designer中可以使用的容器部件有 ...

  6. PyQt(Python+Qt)学习随笔:QHeaderView.ResizeMode取值及含义

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 关于ResizeMode的使用请参考<PyQt(Python+Qt)学习随笔:QTableWi ...

  7. 第9.12节 Python中其他文件操作方式

    一. 引言 本章老猿主要介绍了Python 内置io模块的文件操作相关功能,其实除了内置io模块可以进行文件操作外,Python的不同模块还提供了多种文件操作方式,下面简单将这些模块和方法介绍一下. ...

  8. john快速破解各种散列hash

    0x01 john工具安装: kali系统自带的有,也可以自己安装在其他linux和windows系统上,关于安装步骤网上都有可自行百度. 0x02 john常用选项 具体的其他选项可通过john - ...

  9. Python(一) 快速配置Python编译环境与第一个py文件程序

    1. Python基本语法在此不熬述. 2. 到管网下载Python 3.6.x 版本,与本机匹配的版本,如本机是 win7 64 python-3.6.5-amd64 3. 下载IDE:Python ...

  10. gunicorn简单配置

    Gunicorn配置 # -*- coding: utf-8 -*- import os from multiprocessing import cpu_count bind = "127. ...