SpringBoot3集成Quartz:从入门到实战
前言:本文面向正在使用 Spring Boot 3 的开发者,旨在系统讲解如何集成 Quartz 框架以实现动态、可持久化的定时任务管理。文章将从工程搭建、配置详解、核心用法到常见问题解决方案,带你全面掌握 Spring Boot 3 与 Quartz 的整合实践。
一、简介
Quartz 是一个由 Java 编写的功能丰富的开源作业调度框架,可以集成到几乎任何 Java 应用程序中,并且能够创建和管理多个作业调度。
在实际的业务中,有很多场景依赖定时任务,比如常见的:订单超时处理、数据报表统计分析、会员等周期性管理、业务识别和预警通知等。
二、工程搭建
1、工程结构
一个典型的 Spring Boot 3 集成 Quartz 的项目结构如下:
src/main/java/ ├── com.example.quartzdemo │ ├── config │ ├── controller │ ├── entity │ ├── mapper │ ├── service │ ├── job │ └── QuartzDemoApplication.java src/main/resources/ ├── application.yml ├── quartz_tables_mysql.sql └── static/2、依赖管理
在spring-boot-starter-quartz组件中,实际依赖的是 quartz 组件 2.3.2 版本。使用 Quartz 框架时,需要自定义任务和执行逻辑,以更加灵活的方式管理业务调度。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> <version>${spring-boot.version}</version> </dependency>3、数据库
Quartz 框架使用的表结构在官方提供的 SQL 脚本中,本文选择 MySQL 数据库存储。除此之外自定义两张表:quartz_job任务表和quartz_log任务执行日志表。
Quartz 官方表结构脚本位置:org/quartz/impl/jdbcjobstore/tables_mysql.sql
4、配置文件
在配置文件中使用 Druid 组件连接boot-quartz数据库。对于 Quartz 框架,主要配置数据库存储、调度器的基础信息,以及执行任务的线程池。
spring: # 定时器配置 quartz: # 使用数据库存储 job-store-type: jdbc # 初始化完成后自动启动调度程序 autoStartup: true properties: org: quartz: # 调度器配置 scheduler: instanceName: bootQuartzScheduler instanceId: AUTO # 存储配置 jobStore: class: org.springframework.scheduling.quartz.LocalDataSourceJobStore driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate tablePrefix: qrtz_ isClustered: true misfireThreshold: 12000 clusterCheckinInterval: 15000 useProperties: false # 线程池配置 threadPool: threadNamePrefix: Boot_Job_Pool threadPriority: 5 threadCount: 10 class: org.quartz.simpl.SimpleThreadPool三、Quartz 用法
对于任务管理的相关 Web 接口,采用 Swagger 文档组件,接口和实体类添加注解后,访问IP:Port/swagger-ui/index.html地址即可。
1、初始化加载
在服务启动时执行init初始化方法,查询quartz_job表中运行和暂停状态的任务,判断触发器是否存在,如果不存在则创建,如果存在则更新。
@Service public class QuartzJobService { @Resource private QuartzJobMapper quartzJobMapper ; @Resource private QuartzManage quartzManage; @PostConstruct public void init () { LambdaQueryWrapper<QuartzJob> queryWrapper = new LambdaQueryWrapper<>() ; queryWrapper.in(QuartzJob::getState,JobState.JOB_RUN.getStatus(),JobState.JOB_STOP.getStatus()); List<QuartzJob> jobList = quartzJobMapper.selectList(queryWrapper); jobList.forEach(quartzJob -> { CronTrigger cronTrigger = quartzManage.getCronTrigger(quartzJob.getId()) ; if (Objects.isNull(cronTrigger)){ quartzManage.createJob(quartzJob); } else { quartzManage.updateJob(quartzJob); } }); } }2、新增任务
在创建任务时,需要定义JobKey和TriggerKey的构建规则,Key 需要具备唯一性,通常使用任务表的主键 ID。任务一般是基于 Cron 表达式被调度执行的。
@Component public class QuartzManage { @Resource private Scheduler scheduler ; public void createJob (QuartzJob quartzJob){ try { // 构建任务 JobDetail jobDetail = JobBuilder.newJob(QuartzRecord.class).withIdentity(getJobKey(quartzJob.getId())).build() ; // 构建Cron调度器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder .cronSchedule(quartzJob.getCronExpres()) .withMisfireHandlingInstructionDoNothing() ; // 任务触发器 CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(getTriggerKey(quartzJob.getId())) .withSchedule(scheduleBuilder).build() ; jobDetail.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY,quartzJob); scheduler.scheduleJob(jobDetail,trigger) ; // 状态校验 checkStop(quartzJob) ; } catch (SchedulerException e){ throw new RuntimeException("createJob Fail",e) ; } } }3、更新任务
先通过任务 ID 查询TriggerKey。对于更新来说,最常见的就是 Cron 表达式(即调度规则)的更新,或者任务的执行参数更新。
@Component public class QuartzManage { @Resource private Scheduler scheduler ; public void updateJob(QuartzJob quartzJob) { try { // 查询触发器Key TriggerKey triggerKey = getTriggerKey(quartzJob.getId()); // 构建Cron调度器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder .cronSchedule(quartzJob.getCronExpres()) .withMisfireHandlingInstructionDoNothing(); // 任务触发器 CronTrigger trigger = getCronTrigger(quartzJob.getId()) .getTriggerBuilder().withIdentity(triggerKey) .withSchedule(scheduleBuilder).build(); trigger.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY, quartzJob); // 重新调度任务 scheduler.rescheduleJob(triggerKey, trigger); // 状态校验 checkStop(quartzJob); } catch (SchedulerException e) { throw new RuntimeException("updateJob Fail", e); } } }四、常见问题与解决方案
1、任务不执行
- 检查数据库连接:确保 Quartz 配置的数据库连接正确,表结构已初始化。
- 检查 Cron 表达式:使用在线工具验证 Cron 表达式是否正确。
- 检查任务状态:确认
quartz_job表中任务状态是否为运行状态。
2、集群环境任务重复执行
- 配置集群模式:确保
isClustered: true已启用。 - 检查实例 ID:
instanceId: AUTO确保每个实例有唯一标识。 - 网络时间同步:集群节点间时间需要同步。
3、任务错过触发时间(Misfire)
- 配置 Misfire 策略:在
CronScheduleBuilder中使用withMisfireHandlingInstructionDoNothing()等策略。 - 调整 misfireThreshold:适当增大
misfireThreshold值。
五、总结
Spring Boot 3 集成 Quartz 提供了强大的定时任务管理能力。通过数据库存储、集群支持和灵活的配置,可以满足大多数企业级定时任务需求。在实际使用中,需要注意任务状态管理、Cron 表达式验证和集群环境配置,确保任务调度的稳定性和可靠性。
