基于 Spring Boot SmartLifecycle 扩展点启动 quartz 定时任务
在企业级应用开发中,定时任务是一个非常常见的需求。Spring Boot 提供了非常便捷的方式来集成各种定时任务框架,其中 Quartz 是一个功能强大且灵活的调度框架。本文将详细介绍如何在 Spring Boot 项目中整合 Quartz 定时任务,并介绍采用 SmartLifecycle 优雅的启动 quartz 定时任务。
核心组件
- Job: 用于被调度的任务,JobDetail 描述 Job 的信息,比如类名,作业名称,组名等等,一般通过 JobBuilder 来创建
- Trigger: 定义调用的的规则,一般是 cron 表达式,一个 Job 可以被多个 Trigger 关联,但是一个 Trigger 只能关联一个 Job, 一般通过 TriggerBuilder 来创建
- Schedular: 调度器,根据 Trigger 定义的规则调度任务;
- JobStore: 用于持久化 quartz 的相关数据;
table 介绍
- qrtz_blob_triggers: 以 Blob 类型存储的触发器
- qrtz_calendars: 存放日历信息,quartz 可配置一个日历来指定一个时间范围
- qrtz_cron_triggers: 存放 cron 类型的触发器
- qrtz_fired_triggers: 存放已触发的触发器
- qrtz_job_details: 存放一个 jobDetail 信息
- qrtz_locks: 存储程序的悲观锁的信息(假如使用了悲观锁)
- qrtz_paused_trigger_grps: 存放暂停掉的触发器
- qrtz_scheduler_state: 调度器状态
- qrtz_simple_triggers: 用来存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数。
- qrtz_simprop_triggers:用来存储存储 CalendarIntervalTrigger 和 DailyTimeIntervalTrigger。
- qrtz_triggers: 存储了所有触发器的基本信息
整合 spring-boot-starter-quartz
添加相关依赖
springboot 的版本采用 2.7.15
xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
</dependencies>
定义 Job
@DisallowConcurrentExecution: 同一个任务在任意时间点上只能有一个实例在执行。
java
@Slf4j
@Component
@DisallowConcurrentExecution
public class DemoJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
log.info("执行测试定时任务1");
}
}
@Slf4j
@Component
@DisallowConcurrentExecution
public class DemoJob2 extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
log.info("执行测试定时任务2");
}
}
配置 Job,Trigger,Schedule 之间的关系
java
@Slf4j
@Component
public class QuartzConfig implements SmartLifecycle {
private boolean isRunning = false;
@Autowired
private Scheduler scheduler;
@Override
public void start() {
isRunning = true;
try {
loadJobs();
} catch (SchedulerException e) {
log.info(e.getMessage());
}
}
@Override
public void stop() {
isRunning = false;
}
@Override
public boolean isRunning() {
return isRunning;
}
public void loadJobs() throws SchedulerException {
// 定义 Job 1
JobDetail demoJobDetail = JobBuilder.newJob(DemoJob.class)
.withIdentity("demoJob")
.storeDurably()
.build();
// 定义 Trigger 1
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
CronTrigger trigger = TriggerBuilder
.newTrigger().forJob(demoJobDetail)
.withIdentity("demoJobTrigger")
.withSchedule(cronScheduleBuilder)
.build();
// 定义 Job 2
JobDetail demoJobDetail2 = JobBuilder.newJob(DemoJob2.class)
.withIdentity("demoJob2")
.storeDurably()
.build();
// 定义 Trigger 2
CronScheduleBuilder cronScheduleBuilder2 = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
CronTrigger trigger2 = TriggerBuilder
.newTrigger().forJob(demoJobDetail2)
.withIdentity("demoJobTrigger2")
.withSchedule(cronScheduleBuilder2)
.build();
// 调度 Job 1
scheduler.scheduleJob(demoJobDetail, trigger);
// 调度 Job 2
scheduler.scheduleJob(demoJobDetail2, trigger2);
}
}
这里采用基于 Spring Boot SmartLifecycle 扩展点,自动启动 job
application.yml 配置相关属性
yml
spring:
quartz:
job-store-type: jdbc
wait-for-jobs-to-complete-on-shutdown: true
overwrite-existing-jobs: true
auto-startup: true
startup-delay: 0s
jdbc:
initialize-schema: always # 建议:开发的时候可以先alway,然后把数据库拷贝出来(也可以通过从组件quartz git 仓库拷贝来),通过 flyway 来管理
properties:
org:
quartz:
scheduler:
# 调度器实例名称
instanceName: QuartzScheduler
# 分布式节点ID自动生成
instanceId: AUTO
jobStore:
class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 表前缀
tablePrefix: QRTZ_
# 是否开启集群
isClustered: true
# 数据源别名(自定义)
# dataSource: quartz
# 分布式节点有效性检查时间间隔(毫秒)
clusterCheckinInterval: 10000
useProperties: false
# 线程池配置
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/quartz_db?useSSL=false&serverTimezone=UTC
username: root
password: 123456
测试
启动应用程序可以看到相关的日志执行清空, 以及登录到数据库可以看到相关的表信息
text
2024-11-19 14:17:50.026 INFO 5056 --- [eduler_Worker-1] com.demo.job.crons.DemoJob : 执行测试定时任务1
2024-11-19 14:17:50.036 INFO 5056 --- [eduler_Worker-2] com.demo.job.crons.DemoJob2 : 执行测试定时任务2
2024-11-19 14:17:55.018 INFO 5056 --- [eduler_Worker-3] com.demo.job.crons.DemoJob : 执行测试定时任务1
2024-11-19 14:17:55.036 INFO 5056 --- [eduler_Worker-4] com.demo.job.crons.DemoJob2 : 执行测试定时任务2