一、Quartz 是什么?

Quartz Scheduler 是一个 Java 的“任务调度框架(Job Scheduling Framework)”。

它的核心作用是:

在指定时间、按指定规则,自动执行某些 Java 代码。

Quartz 适合场景:

  • 每天凌晨自动对账
  • 每5分钟同步一次数据
  • 每月1号生成报表
  • 延迟30分钟取消未支付订单
  • 定时扫描FTP文件
  • 自动重试失败任务
  • 对账系统
  • 财务结算
  • 大数据同步
  • 定时推送
  • 自动重试
  • 批量任务
  • 分布式定时任务
  • T+1清算
  • 夜间跑批
  • 自动生成账单
  • 数据同步
  • 30 分钟未支付自动取消
  • MQ 失败后的重试机制

它比 Spring Boot 自带的 @Scheduled 更强大、更专业。

Quartz 官网

Spring Boot Quartz 文档

Quartz github地址


二、Quartz 能解决什么问题?

1. 替代简单的 while + sleep

很多初学者会写:

while(true){
    doTask();
    Thread.sleep(60000);
}

问题:

  • 不易管理
  • 无法动态修改
  • 容易线程泄漏
  • 不支持复杂时间表达式
  • 不支持失败恢复

Quartz 专门解决这些问题。

2. 支持复杂定时规则

Spring 自带:

@Scheduled(cron = "0 0 1 * * ?")

只能简单定时。

而 Quartz 支持:

  • Cron表达式
  • 固定间隔
  • 指定开始结束时间
  • 指定重复次数
  • 动态修改时间
  • 暂停/恢复任务

3. 持久化任务

Quartz 可以把任务存数据库。

即使:

  • 服务重启
  • JVM崩溃
  • 机器宕机

任务仍然不会丢失。


4. 集群调度

多个服务器同时部署时:

Quartz 可以保证:

一个任务只会被其中一台机器执行。

适合:

  • 微服务
  • 分布式系统
  • 高可用系统

5. 动态管理任务

运行中:

  • 新增任务
  • 删除任务
  • 修改Cron
  • 立即执行

不需要重启项目。


三、Quartz 核心概念

Quartz 最重要的几个对象:

概念作用
Job真正执行的任务
JobDetailJob 的描述信息
Trigger触发规则
Scheduler调度器

执行流程:

Scheduler
    ↓
Trigger(什么时候执行)
    ↓
JobDetail
    ↓
Job(调用 execute() 执行具体逻辑)

四、Quartz 和 Spring @Scheduled 区别

对比Quartz@Scheduled
简单程度较复杂非常简单
动态修改支持不支持
持久化支持不支持
集群支持不支持
失败恢复支持不支持
数据库存储支持不支持
适合企业级是一般简单任务

五、引入 Quartz

如果你想使用 jdk8 并且没有使用 springboot 框架,Maven依赖:

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <!-- 2.4.1 是支持jdk8的最后一个版本-->
    <version>2.4.1</version>
    <scope>compile</scope>
</dependency>

如果你使用 spring boot 框架,Maven依赖:

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

六、Quartz 使用示例


1.普通使用(非SpringBoot)

第一步:创建 Job

Job 就是真正执行的任务。

import org.quartz.Job;
import org.quartz.JobExecutionContext;

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext context) {
        System.out.println("Hello Quartz:" + new java.util.Date());
    }
}

第二步:创建 Scheduler

package demo;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

public class QuartzDemo {

    public static void main(String[] args) throws Exception {

        // 1. 创建 JobDetail
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("helloJob")
                .build();

        // 2. 创建 Trigger
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("helloTrigger")
                .startNow()
            	//每隔5秒执行一次
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                .withIntervalInSeconds(5)
                                .repeatForever()
                )
                .build();

        // 3. 获取 Scheduler
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        // 4. 注册任务和触发器
        scheduler.scheduleJob(jobDetail, trigger);

        // 5. 启动调度器
        scheduler.start();
    }
}

运行效果:

Hello Quartz:Sat May 24 10:00:00
Hello Quartz:Sat May 24 10:00:05
Hello Quartz:Sat May 24 10:00:10

2.springboot中使用

第一步:创建 Job

@Component
public class HelloJob extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext context) {

        System.out.println("处理订单");
    }
}

第一步:创建配置类

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QuartzConfig {

    /**
     * 定义Job
     */
    @Bean
    public JobDetail helloJobDetail() {
        return JobBuilder.newJob(HelloJob.class)
                .withIdentity("helloJob")
                .storeDurably()
                .build();
    }

    /**
     * 定义触发器
     */
    @Bean
    public Trigger helloTrigger() {
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
            			//每个5秒执行一次
                        .withIntervalInSeconds(5)
                        .repeatForever();

        return TriggerBuilder.newTrigger()
                .forJob(helloJobDetail())
                .withIdentity("helloTrigger")
                .withSchedule(scheduleBuilder)
                .build();
    }
}

七、Cron 表达式

Quartz 最常用的是 Cron。

1.常见 Cron 示例

表达式含义
0/5 * * * * ?每5秒
0 0/1 * * * ?每1分钟
0 0 1 * * ?每天1点
0 0 1 1 * ?每月1号1点
0 0 9 ? * MON每周一9点
0 0,2,4 13 * * ?每天的 13:00、13:02、13:04 分别执行一次

2.Quartz Cron 和 Linux Cron 区别

Quartz 多一位“秒”。

Linux:

分 时 日 月 周

Quartz:

秒 分 时 日 月 周 年(可选)

3.CronTrigger 使用 Cron 示例

@Bean
public Trigger cronTrigger() {
	//每10秒执行一次
    CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule("0/10 * * * * ?");

    return TriggerBuilder.newTrigger()
            .forJob(helloJobDetail())
            .withIdentity("cronTrigger")
            .withSchedule(cron)
            .build();
}

八、Quartz 常用 API

1.JobBuilder

创建任务。

JobBuilder.newJob(HelloJob.class)

2.TriggerBuilder

创建触发器。

TriggerBuilder.newTrigger()

3.SimpleScheduleBuilder

简单周期任务。

.withIntervalInSeconds(5)
.repeatForever()

4.CronScheduleBuilder

Cron 定时规则。

cronSchedule("0 0 12 * * ?")

5.JobDataMap(传递参数)

Quartz 支持给任务传参。

设置参数

JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
        .usingJobData("name", "Tom")
        .build();

获取参数

非 springboot 框架:

import org.quartz.Job;
import org.quartz.JobExecutionContext;

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext context) {
    	//获取 JobDetail 中的参数
        JobDataMap map = context.getMergedJobDataMap();
        String name = map.getString("name");
        
        System.out.println("Hello Quartz:" + name);
    }
}

springboot 框架:

@Component
public class HelloJob extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext context) {
    	//获取 JobDetail 中的参数
        JobDataMap map = context.getMergedJobDataMap();
        String name = map.getString("name");
        
        System.out.println("Hello Quartz:" + name);
    }
}

九、动态创建任务(常用)

企业里经常:

  • 数据库存cron
  • 页面动态新增任务
  • 用户自定义任务

这种不能写死 @Bean。

需要动态操作:


1.动态新增任务

@Autowired
private Scheduler scheduler;

public void addJob() throws Exception {

    JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
            .withIdentity("job1", "group1")
            .build();

    CronTrigger trigger = TriggerBuilder.newTrigger()
            .withIdentity("trigger1", "group1")
            .withSchedule(
                    CronScheduleBuilder
                            .cronSchedule("0/5 * * * * ?")
            )
            .build();

    scheduler.scheduleJob(jobDetail, trigger);
}

2.删除任务

scheduler.deleteJob(
    JobKey.jobKey("job1", "group1")
);

3.暂停任务

scheduler.pauseJob(
    JobKey.jobKey("job1", "group1")
);

4.恢复任务

scheduler.resumeJob(
    JobKey.jobKey("job1", "group1")
);

5.修改Cron

TriggerKey triggerKey =
        TriggerKey.triggerKey("trigger1", "group1");

CronTrigger trigger =
        TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .withSchedule(
                        CronScheduleBuilder
                                .cronSchedule("0/30 * * * * ?")
                )
                .build();

scheduler.rescheduleJob(triggerKey, trigger);

十、Quartz 持久化(重要)

默认 Quartz 是内存模式。

重启后任务丢失。

企业通常使用:

MySQL + Quartz JDBC JobStore

任务会存数据库。


1.application.yml

spring:
  quartz:
    job-store-type: jdbc
    jdbc:
      initialize-schema: always

2.Quartz 表结构

Quartz 会自动创建:

QRTZ_JOB_DETAILS
QRTZ_TRIGGERS
QRTZ_CRON_TRIGGERS
QRTZ_FIRED_TRIGGERS
...

大约十几张表。


十一、Quartz 集群与线程池(重点)

多个服务实例:

A服务器
B服务器
C服务器

Quartz 集群可保证:

同一任务不会重复执行

只会:

A执行
B/C等待

1.集群配置

spring:
  quartz:
    properties:
      org:
        quartz:
          scheduler:
            instanceName: clusteredScheduler
          jobStore:
            isClustered: true

2.Quartz 线程池

Quartz 自己维护线程池。

spring:
  quartz:
    properties:
      org:
        quartz:
          threadPool:
            threadCount: 10

表示:

同时最多10个任务并发执行

十二、Quartz 防止任务并发执行

默认:

同一个 Job 可能并发执行。

例如:

任务执行10秒
但cron每5秒触发

会导致:

多个任务同时执行

解决:

@DisallowConcurrentExecution
public class HelloJob implements Job {
}

十三、Quartz 缺点和常见问题


1.缺点

问题说明
配置复杂比 @Scheduled 重
学习成本较高概念较多
集群依赖数据库配置麻烦
大规模任务性能一般超大规模需专门调度平台

2.常见问题

(1). 任务重复执行

原因:

多节点部署但没开启集群。


(2). Job 并发问题

解决:

@DisallowConcurrentExecution

(3). 任务阻塞

原因:

Quartz线程池太小。


(4). 数据库锁竞争

Quartz 集群本质依赖数据库锁。

高并发任务过多时:

可能有锁竞争。


十四、现在企业里还有哪些替代方案?

除了 Quartz:

框架特点
XXL-Job国内最流行
Elastic-Job分布式
PowerJob新一代
SchedulerX阿里云
Spring Scheduled简单轻量

企业里现在最常用的是?

国内互联网:

  • XXL-Job 很多
  • Quartz 也非常多
  • Spring Scheduled 最基础

银行、证券、传统企业:

Quartz 仍然大量存在。

因为:

  • 稳定
  • 成熟
  • 历史悠久
  • 功能完整

十五、推荐学习路线

第一阶段

先掌握:

  • Job
  • Trigger
  • Cron
  • Scheduler

第二阶段

学习:

  • 动态任务
  • Job参数
  • 并发控制

第三阶段(重点)

学习:

  • JDBC持久化
  • 集群模式
  • 分布式任务

第四阶段

再学习:

  • XXL-Job
  • Elastic-Job
  • PowerJob
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐