Quartz

Quartz 是 Java 生态中最成熟的任务调度框架,支持 Cron 表达式、简单触发器、集群调度(基于数据库锁),可嵌入任何 Java 应用。适合单体或小规模集群的定时任务场景。

分布式大规模场景推荐 XXL-Job(有 Web 管控台、执行日志、失败重试等)。


核心概念

概念说明
Job任务逻辑,实现 execute() 方法
JobDetailJob 的描述(名称、组、数据)
Trigger触发规则(何时执行)
Scheduler调度器,管理 Job 和 Trigger
JobDataMap向 Job 传递参数的 Map

Spring Boot 集成

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

定义 Job

@Component
public class OrderCleanJob implements Job {
 
    @Autowired
    private OrderService orderService;
 
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        String param = context.getMergedJobDataMap().getString("param");
        orderService.cleanExpiredOrders();
    }
}

注册 JobDetail 和 Trigger

@Bean
public JobDetail orderCleanJobDetail() {
    return JobBuilder.newJob(OrderCleanJob.class)
        .withIdentity("orderCleanJob", "cleanGroup")
        .usingJobData("param", "value")
        .storeDurably()
        .build();
}
 
@Bean
public Trigger orderCleanTrigger(JobDetail orderCleanJobDetail) {
    return TriggerBuilder.newTrigger()
        .forJob(orderCleanJobDetail)
        .withIdentity("orderCleanTrigger", "cleanGroup")
        .withSchedule(CronScheduleBuilder.cronSchedule("0 0 2 * * ?"))
        .build();
}

触发器类型

CronTrigger

CronScheduleBuilder.cronSchedule("0 0/30 * * * ?")   // 每 30 分钟

SimpleTrigger(固定间隔)

Trigger trigger = TriggerBuilder.newTrigger()
    .startNow()
    .withSchedule(SimpleScheduleBuilder.simpleSchedule()
        .withIntervalInSeconds(30)
        .repeatForever())
    .build();

Cron 表达式

格式:秒 分 时 日 月 周 [年]

表达式含义
0 0 2 * * ?每天凌晨 2:00
0 0/30 * * * ?每 30 分钟
0 0 9-18 * * MON-FRI工作日 9~18 点每小时整点
0 0 12 ? * WED每周三 12:00
0 0 0 1 * ?每月 1 日 0:00
0 15 10 L * ?每月最后一天 10:15

特殊字符:*(所有)、?(日/周中不指定)、/(步长)、L(最后)、#(第几个星期几)


@Scheduled 注解(简化方案)

Spring 内置,无需 Quartz 依赖,适合简单单机场景:

@Component
@EnableScheduling
public class SimpleTask {
 
    @Scheduled(cron = "0 0 2 * * ?")
    public void cleanOrders() { ... }
 
    @Scheduled(fixedRate = 30000)    // 固定频率(ms),上次开始后计时
    public void syncData() { ... }
 
    @Scheduled(fixedDelay = 10000)   // 固定延迟(ms),上次结束后计时
    public void checkStatus() { ... }
}

集群模式

Quartz 集群依赖数据库行锁保证同一时刻只有一个节点执行任务。

建表

官方提供建表 SQL(tables_mysql_innodb.sql):

表名作用
QRTZ_JOB_DETAILSJob 详情
QRTZ_TRIGGERS触发器
QRTZ_CRON_TRIGGERSCron 触发器
QRTZ_FIRED_TRIGGERS正在执行的触发器
QRTZ_LOCKS集群锁
QRTZ_SCHEDULER_STATE节点心跳

配置

spring:
  quartz:
    job-store-type: jdbc
    jdbc:
      initialize-schema: never      # 手动建表
    properties:
      org.quartz.scheduler.instanceId: AUTO
      org.quartz.jobStore.isClustered: true
      org.quartz.jobStore.clusterCheckinInterval: 10000

Misfire(错过触发)处理

任务执行超时或宕机导致触发时间已过:

// CronTrigger
CronScheduleBuilder.cronSchedule("0 0 2 * * ?")
    .withMisfireHandlingInstructionDoNothing()       // 忽略,等下次
    .withMisfireHandlingInstructionFireAndProceed()  // 立即执行一次
 
// SimpleTrigger
SimpleScheduleBuilder.simpleSchedule()
    .withMisfireHandlingInstructionFireNow()         // 立即执行

动态管理任务

@Autowired
private Scheduler scheduler;
 
// 新增
scheduler.scheduleJob(jobDetail, trigger);
 
// 暂停 / 恢复
scheduler.pauseJob(JobKey.jobKey("orderCleanJob", "cleanGroup"));
scheduler.resumeJob(JobKey.jobKey("orderCleanJob", "cleanGroup"));
 
// 修改 Cron
TriggerKey key = TriggerKey.triggerKey("orderCleanTrigger", "cleanGroup");
CronTrigger newTrigger = TriggerBuilder.newTrigger()
    .withSchedule(CronScheduleBuilder.cronSchedule("0 0 3 * * ?"))
    .build();
scheduler.rescheduleJob(key, newTrigger);
 
// 删除
scheduler.deleteJob(JobKey.jobKey("orderCleanJob", "cleanGroup"));

Quartz vs XXL-Job

维度QuartzXXL-Job
部署方式嵌入应用独立调度中心 + 执行器
管控台内置 Web UI
执行日志完整日志查询
失败重试需自行实现内置
分片执行不支持支持分片广播
路由策略轮询、故障转移等多种
适用规模单体 / 小集群中大型分布式系统

相关链接

  • XXL-Job — 分布式任务调度,有 Web 管控台和执行日志
  • MySQL — Quartz 集群模式依赖数据库存储调度状态
  • Zookeeper — 分布式任务协调的另一种方案