3. Quartz框架详解

Quartz 是一个功能丰富的开源作业调度框架,几乎已成为 Java 生态中任务调度的事实标准。本章深入剖析 Quartz 的架构设计、核心 API、Cron 表达式语法以及生产级持久化配置,为后续调度平台选型与部署打下坚实基础。

3.1 Quartz 整体架构

Quartz 采用模块化分层设计,核心组件包括调度器(Scheduler)、任务(JobDetail)、触发器(Trigger)以及任务存储(JobStore)。下图展示了 Quartz 运行时的主要组件及其协作关系:

Quartz 整体架构图 Scheduler(调度器) JobStore(任务存储) JobDetail(任务定义) Trigger(触发器) 数据库 / RAMStore Scheduler 统一管理 JobDetail 与 Trigger 的注册、匹配与执行,JobStore 负责持久化调度状态
架构要点:
  • Scheduler 是调度的总控入口,负责注册任务、管理触发器、启动/暂停/停止调度。
  • JobStore 是调度数据的持久化层,支持内存(RAMJobStore)和数据库(JDBCJobStore)两种模式。
  • JobDetail 与 Trigger 是多对多关系:一个 JobDetail 可绑定多个 Trigger,一个 Trigger 只能绑定一个 JobDetail。

3.2 核心 API 详解

Quartz 对外暴露三个核心接口:Scheduler、JobDetail 和 Trigger。理解这三个接口的职责与用法是掌握 Quartz 的关键。

3.2.1 Scheduler — 调度总控

Scheduler 是 Quartz 的门面接口,所有调度操作均通过它完成。常用方法如下:

方法说明典型场景
start()启动调度器,开始处理触发器应用初始化后调用
shutdown()关闭调度器,释放资源应用关闭或销毁时调用
scheduleJob(JobDetail, Trigger)注册任务并绑定触发器动态添加定时任务
unscheduleJob(TriggerKey)移除指定触发器取消某个定时任务
pauseJob(JobKey)暂停指定任务临时停止任务执行
resumeJob(JobKey)恢复指定任务重新启动暂停的任务

3.2.2 JobDetail — 任务定义

JobDetail 描述一个具体的可执行任务。它通过 JobBuilder 构建,包含任务类、任务名称、分组以及自定义数据(JobDataMap)。

// 构建 JobDetail 示例
JobDetail job = JobBuilder.newJob(MyJob.class)
    .withIdentity("myJob", "group1")
    .usingJobData("threshold", 0.75)
    .usingJobData("retryCount", 3)
    .build();
最佳实践: 使用 JobDataMap 传递运行时参数,避免在 Job 实现类中硬编码配置。JobDetail 一旦创建,其 JobDataMap 在多次触发间保持不变。

3.2.3 Trigger — 触发器

Trigger 决定任务何时执行。Quartz 提供两种主要触发器:

  • SimpleTrigger:适用于固定间隔的重复执行,如“每 5 分钟执行一次,共执行 10 次”。
  • CronTrigger:基于 Cron 表达式的复杂调度,支持“每周一至周五上午 10:15”等场景。
// SimpleTrigger 示例:每 10 秒执行一次,无限重复
Trigger trigger = TriggerBuilder.newTrigger()
    .withIdentity("myTrigger", "group1")
    .startNow()
    .withSchedule(SimpleScheduleBuilder.simpleSchedule()
        .withIntervalInSeconds(10)
        .repeatForever())
    .build();

// CronTrigger 示例:每天上午 10:30 执行
Trigger cronTrigger = TriggerBuilder.newTrigger()
    .withIdentity("cronTrigger", "group1")
    .withSchedule(CronScheduleBuilder.cronSchedule("0 30 10 * * ?"))
    .build();

3.3 Cron 表达式详解

Cron 表达式是 Quartz 最强大的调度语法,由 6 或 7 个字段组成,精确控制秒、分、时、日、月、周、年(可选)。

位置字段取值范围允许特殊字符
1秒0–59, - * /
2分0–59, - * /
3时0–23, - * /
4日1–31, - * ? / L W
5月1–12 或 JAN–DEC, - * /
6周1–7 或 SUN–SAT, - * ? / L #
7年(可选)1970–2099, - * /

特殊字符含义:

  • *:所有值,如“每分钟”的分钟字段用 *。
  • ?:不指定值,仅用于日和周字段,避免冲突。
  • -:范围,如 10-15 表示 10 到 15。
  • /:步长,如 0/5 表示从 0 开始每 5 个单位。
  • L:最后,如 L 在日字段表示当月最后一天。
  • W:最近工作日,如 15W 表示 15 号最近的工作日。
  • #:第几个星期几,如 3#2 表示当月第二个星期三。

常用 Cron 表达式示例:

表达式含义
0 0 12 * * ?每天中午 12:00
0 0/5 * * * ?每 5 分钟执行一次
0 0 8-18/2 * * ?每天 8:00 到 18:00 之间每 2 小时执行
0 0 10 ? * MON-FRI每周一至周五上午 10:00
0 0 0 L * ?每月最后一天的午夜
0 15 10 ? * 6#3每月第三个星期五上午 10:15
常见陷阱: 日和周字段同时使用非 ? 值会导致表达式无效。例如 0 0 12 15 * 5 是错误的,应改为 0 0 12 15 * ? 或 0 0 12 ? * 5。

3.4 持久化配置

Quartz 默认使用 RAMJobStore,调度信息仅保存在内存中,应用重启后所有任务丢失。生产环境必须配置 JDBCJobStore 实现持久化。

3.4.1 持久化架构

JDBCJobStore 通过数据库表存储 JobDetail、Trigger、Calendar、Scheduler 状态等信息。Quartz 官方提供 11 张核心表,覆盖主流数据库(MySQL、PostgreSQL、Oracle、SQL Server 等)。

Quartz JDBCJobStore 持久化架构 Quartz Scheduler JDBCJobStore Quartz 核心表(11 张) QRTZ_JOB_DETAILS QRTZ_TRIGGERS QRTZ_CRON_TRIGGERS QRTZ_SIMPLE_TRIGGERS QRTZ_BLOB_TRIGGERS QRTZ_CALENDARS JDBCJobStore 通过 DataSource 连接数据库,将调度状态持久化到 11 张标准表中 支持集群模式(Clustered Scheduler),实现高可用与故障转移

3.4.2 核心配置项

在 quartz.properties 中配置 JDBCJobStore 的关键参数:

# 指定 JobStore 实现类
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX

# 数据源名称(需同时配置 DataSource)
org.quartz.jobStore.dataSource = myDS

# 数据库方言(根据数据库类型选择)
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

# 表前缀(默认 QRTZ_)
org.quartz.jobStore.tablePrefix = QRTZ_

# 是否启用集群模式
org.quartz.jobStore.isClustered = true

# 集群检查间隔(毫秒)
org.quartz.jobStore.clusterCheckinInterval = 20000

# 数据源配置
org.quartz.dataSource.myDS.driver = com.mysql.cj.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz_db
org.quartz.dataSource.myDS.user = quartz_user
org.quartz.dataSource.myDS.password = quartz_pass
org.quartz.dataSource.myDS.maxConnections = 10

3.4.3 集群模式注意事项

配置项推荐值说明
isClusteredtrue启用集群,多个节点共享同一数据库
clusterCheckinInterval20000 (20s)节点心跳检测间隔,过短增加 DB 压力,过长延迟故障发现
maxConnections≥ 节点数 × 3确保每个节点有足够的数据库连接
数据库表索引按官方脚本创建缺少索引会导致集群锁竞争和性能下降
生产建议:
  • 首次部署时使用 Quartz 官方提供的 tables_<db>.sql 脚本创建表结构,不要手动建表。
  • 集群模式下所有节点必须使用相同的 instanceName 和 tablePrefix。
  • 建议将 Quartz 表放在独立 Schema 中,避免与业务表混用影响性能。

3.5 本章小结