什么是 Quartz?
Quartz 的核心是三个基本概念:

- 调度器:这是 Quartz 的中枢,负责管理所有调度相关的组件(
Job,Trigger,Scheduler本身),你可以把它想象成一个“引擎”,驱动着所有定时任务的执行。 - 任务:这是你想要执行的具体工作,在 Quartz 中,
Job是一个接口,你只需要实现这个接口的execute()方法,将你的业务逻辑写在里面即可。 - 触发器:它决定了
Job何时以及如何执行,你可以设置一个触发器让它每天凌晨 2 点执行,或者每隔 10 分钟执行一次,一个Job可以绑定多个Trigger,但一个Trigger在同一时间只能绑定一个Job。
核心组件详解
1 Job (任务)
Job 是一个接口,你只需要实现它。
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 这里写你的业务逻辑
System.out.println("Hello, Quartz! MyJob is running at " + new Date());
// 你可以从 JobExecutionContext 中获取更多信息
// 获取 Trigger 的名称
String triggerName = context.getTrigger().getKey().getName();
System.out.println("Trigger Name: " + triggerName);
}
}
2 Trigger (触发器)
Trigger 用来定义调度规则,最常用的两种触发器是:
- SimpleTrigger:用于简单的调度场景,在指定时间执行一次,或者在指定时间开始,然后每隔一段时间重复执行 N 次。
- CronTrigger:功能更加强大,基于 Cron 表达式,适用于复杂的调度规则,每周一、周三、周五的上午 9:30 执行”。
Cron 表达式示例:
| 表达式 | 含义 |
|---|---|
0 0 12 * * ? |
每天中午12点触发 |
0 15 10 ? * * |
每天上午10:15触发 |
0 15 10 * * ? 2025 |
在2025年的每天上午10:15触发 |
0 * 14 * * ? |
在每天下午2点到下午2点59分之间的每分钟触发 |
0 0/5 14 * * ? |
在每天下午2点到下午2点55分之间的每5分钟触发 |
0 0/5 14,18 * * ? |
在每天下午2点到2点55分和下午6点到6点55分之间的每5分钟触发 |
0 0/30 9-17 * * ? |
朝九晚五工作时间内每半小时触发 |
0 0 0 1 * ? |
每月1号凌晨12点触发 |
0 15 10 ? * MON-FRI |
周一至周五的上午10:15触发 |
0 15 10 L * ? |
每月最后一天的上午10:15触发 |
0 15 10 ? * 6L |
每月最后一个星期五的上午10:15触发 |
0 15 10 ? * 6#3 |
每月的第三个星期五的上午10:15触发 |
3 Scheduler (调度器)
Scheduler 是总指挥,它将 Job 和 Trigger 结合起来,并按照 Trigger 的定义来执行 Job。
快速上手示例 (原生 API)
下面是一个完整的、简单的 Quartz 示例,展示了如何创建、调度并运行一个任务。
步骤 1: 添加依赖
在你的 pom.xml 文件中添加 Quartz 的核心依赖。
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version> <!-- 建议使用较新稳定版本 -->
</dependency>
<!-- 为了方便日志输出,可以添加 slf4j 实现 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
步骤 2: 编写 Job 类
创建一个实现 Job 接口的类。
package com.example.demo;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 获取当前时间
Date date = new Date();
// 打印任务执行信息
System.out.println("HelloJob 正在执行,时间: " + date);
}
}
步骤 3: 编写调度代码
这是将所有组件串联起来的主程序。
package com.example.demo;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzSchedulerDemo {
public static void main(String[] args) throws SchedulerException {
// 1. 创建一个 SchedulerFactory 工厂实例
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
// 2. 从工厂中获取一个 Scheduler 调度器实例
Scheduler scheduler = schedulerFactory.getScheduler();
// 3. 创建 JobDetail 实例,并与 HelloJob 类绑定
// JobDetail 是任务的详细配置,包括任务的名称、分组以及关联的 Job 类
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "group1") // 定义 Job 的名称和分组
.build();
// 4. 创建 Trigger 实例,定义触发规则
// 使用 CronTrigger,设置每 5 秒执行一次
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1") // 定义 Trigger 的名称和分组
.startNow() // 立即生效
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) // Cron 表达式
.build();
// 5. 将 Job 和 Trigger 绑定到 Scheduler 中,并调度执行
scheduler.scheduleJob(jobDetail, trigger);
// 6. 启动调度器
scheduler.start();
// 为了让程序不退出,可以主线程睡眠
try {
Thread.sleep(60000); // 睡眠60秒,观察任务执行
} catch (InterruptedException e) {
e.printStackTrace();
}
// 7. 关闭调度器
// scheduler.shutdown();
}
}
运行结果: 你会看到控制台每隔 5 秒打印一次 "HelloJob 正在执行,时间: ...",持续 60 秒。
高级特性与最佳实践
在实际项目中,我们通常不会直接使用原生 API,而是结合 Spring/Spring Boot 来使用,这样能更好地管理生命周期和依赖注入。
1 Spring Boot 集成 (推荐)
Spring Boot 提供了非常方便的 spring-boot-starter-quartz,可以零配置快速集成。
步骤 1: 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
步骤 2: 编写 Job 类
Spring Boot 会自动扫描 @Component 或 @Service 注解的 Job 实现类。关键点:Job 类需要有一个无参构造函数,因为 Spring 会通过反射创建实例。
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class MySpringJob implements Job {
// Spring 会自动注入依赖,Service
// @Autowired
// private MyBusinessService myBusinessService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("MySpringJob 正在执行,时间: " + new Date());
// 这里可以调用你的业务逻辑
// myBusinessService.doSomething();
}
}
步骤 3: 配置 Job 和 Trigger
在 Spring Boot 的配置类中,你可以使用 @Bean 来定义 JobDetail 和 Trigger。
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuartzConfig {
// 1. 定义 JobDetail
@Bean
public JobDetail myJobDetail() {
// 使用 JobBuilder 构建 JobDetail
// ofType 指定 Job 的实现类
// storeDurably 表示即使没有 Trigger 关联,也持久化保存 JobDetail
return JobBuilder.newJob(MySpringJob.class)
.withIdentity("mySpringJob", "springGroup")
.storeDurably()
.build();
}
// 2. 定义 Trigger
@Bean
public Trigger myJobTrigger() {
// 使用 TriggerBuilder 构建 Trigger
// forJob 关联上面定义的 JobDetail
// withSchedule 设置 Cron 表达式
return TriggerBuilder.newTrigger()
.forJob(myJobDetail()) // 关联 JobDetail
.withIdentity("mySpringJobTrigger", "springGroup")
.withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?")) // 每10秒执行一次
.build();
}
}
启动你的 Spring Boot 应用,Quartz 就会自动加载并执行这个定时任务。
2 持久化
默认情况下,Quartz 将 Job 和 Trigger 的信息保存在内存中,这意味着如果应用重启,所有调度信息都会丢失。
持久化 是将调度信息(Job, Trigger, Calendar 等)保存到数据库中,这样做的好处是:
- 应用重启后,之前的调度任务不会丢失,会按照之前的配置继续执行。
- 可以实现集群部署,多个节点共享同一个数据库,协同工作。
如何实现持久化?
- 添加数据库驱动依赖:如
mysql-connector-java。 - 创建 Quartz 表:Quartz 官方提供了多种数据库的 SQL 脚本(在
quartz包的docs/dbTables目录下),你需要在你选择的数据库中执行这些脚本。 - 配置数据源:在
application.properties或application.yml中配置 Quartz 使用的数据库连接信息。
application.properties 示例:
# Quartz 相关配置 spring.quartz.job-store-type=jdbc # 使用 JDBC 方式持久化 spring.quartz.jdbc.initialize-schema=never # 不让 Spring Boot 自动创建表,因为我们手动执行了 # 配置 Quartz 使用的数据源 (可以复用 Spring 的主数据源,也可以单独配置) spring.quartz.properties.org.quartz.dataSource.myDS.connectionProviderUrl=jdbc:mysql://localhost:3306/quartz_db?useSSL=false&serverTimezone=UTC spring.quartz.properties.org.quartz.dataSource.myDS.driverClass=com.mysql.cj.jdbc.Driver spring.quartz.properties.org.quartz.dataSource.myDS.user=root spring.quartz.properties.org.quartz.dataSource.myDS.password=yourpassword
3 动态修改 Cron 表达式
在实际业务中,我们经常需要动态修改任务的执行周期,Spring Boot 集成下,可以通过 Scheduler API 来实现。
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;
@Service
public class DynamicQuartzService {
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
/**
* 更新任务的 Cron 表达式
* @param jobName 任务名
* @param jobGroup 任务组
* @param newCronExpression 新的 Cron 表达式
*/
public void updateCronExpression(String jobName, String jobGroup, String newCronExpression) throws SchedulerException {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
// 获取 Trigger 的 Key
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
// 获取旧的 Trigger
CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 如果旧的 Trigger 不存在,则创建一个新的
if (oldTrigger == null) {
// 获取 JobDetail
JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(jobName, jobGroup));
if (jobDetail == null) {
throw new RuntimeException("Job " + jobName + " not found.");
}
// 创建新的 Trigger
CronTrigger newTrigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
.forJob(jobDetail)
.withSchedule(CronScheduleBuilder.cronSchedule(newCronExpression))
.build();
// 调度新的 Job
scheduler.scheduleJob(jobDetail, newTrigger);
} else {
// 修改旧的 Trigger
CronTrigger newTrigger = (CronTrigger) oldTrigger.getTriggerBuilder()
.withSchedule(CronScheduleBuilder.cronSchedule(newCronExpression))
.build();
// 移除旧的 Trigger,并调度新的 Trigger
scheduler.rescheduleJob(triggerKey, newTrigger);
}
}
}
| 特性 | 原生 API | Spring Boot 集成 |
|---|---|---|
| 易用性 | 较低,需要手动管理 Scheduler 生命周期 |
高,自动配置,开箱即用 |
| 依赖注入 | 不支持,Job 内部无法直接注入 Spring Bean |
支持,Job 类可以像普通 Spring Bean 一样注入依赖 |
| 配置方式 | Java 代码硬编码 | application.properties / @Bean 注解,更灵活 |
| 推荐场景 | 学习 Quartz 原理、非 Spring 项目 | 绝大多数 Java 项目,尤其是 Spring/Spring Boot 项目 |
Quartz 是一个非常成熟和强大的调度框架,掌握它对于处理后台定时任务、数据处理、报表生成等场景至关重要,从原生 API 入手有助于理解其核心概念,但在实际开发中,强烈推荐使用 Spring Boot 集成方式,以获得更高的开发效率和更好的可维护性。
