Quartz 调度框架:Java 任务调度基石
FreeGuideOnline
最新
2026-06-30
java public class MyJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 在这里编写任务逻辑,例如发送邮件、生成报表等 System.out.println("任务执行中..."); } }
### 2. 触发器(Trigger)
触发器决定了任务“何时”执行。Quartz 提供了两种最常用的触发器:
- **SimpleTrigger**:适合固定间隔、重复次数的场景(如每 30 秒运行一次,共 10 次)。
- **CronTrigger**:基于 Cron 表达式定义复杂的调度规则,如“每天上午 9:15”或“每周一至周五 18:00”。
### 3. 调度器(Scheduler)
`Scheduler` 是 Quartz 的心脏,负责将 Job 和 Trigger 组织在一起并启动执行。你可以通过 `SchedulerFactory` 创建 `Scheduler` 实例。一个应用通常只有一个调度器实例(集群模式下为每个节点一个)。
## 快速入门:搭建你的第一个调度任务
### 环境准备
在 Maven 项目 `pom.xml` 中添加 Quartz 依赖:
```xml
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
步骤 1:创建 Job 类
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Hello Quartz! 当前时间: " + new Date());
}
}
步骤 2:编写调度程序
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzExample {
public static void main(String[] args) throws SchedulerException {
// 1. 创建 Scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2. 定义 JobDetail,关联我们的 HelloJob 类
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("helloJob", "group1")
.build();
// 3. 创建 SimpleTrigger:立即启动,每 3 秒执行一次,重复 forever
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("simpleTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever())
.build();
// 4. 将 Job 和 Trigger 注册到调度器
scheduler.scheduleJob(job, trigger);
// 5. 启动调度器
scheduler.start();
// 保持主线程存活一段时间,便于观察任务执行
Thread.sleep(20000);
scheduler.shutdown();
}
}
运行程序即可看到控制台每 3 秒打印一次问候语。
CronTrigger 与 Cron 表达式
CronTrigger 是 Quzrtz 中最强大的触发器,它使用 Cron 表达式来精确定义执行时间。
一个 Cron 表达式由 7 个字段组成(最后一个年份可选):
秒 分 时 日 月 星期 [年]
常见示例:
| 表达式 | 含义 |
|---|---|
0 15 10 * * ? |
每天上午 10:15 执行 |
0 0/5 14 * * ? |
每天下午 2:00 开始,每隔 5 分钟执行一次 |
0 30 9 ? * MON-FRI |
每周一到周五上午 9:30 执行 |
0 0 12 L * ? |
每月最后一天中午 12:00 执行 |
使用 CronTrigger 的代码片段:
Trigger cronTrigger = TriggerBuilder.newTrigger()
.withIdentity("cronTrigger", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * * * ?")) // 每分钟一次
.build();
任务状态与持久化
默认情况下,Quartz 将任务和触发器存储在内存中(RAMJobStore),应用重启后所有调度信息会丢失。生产环境通常需要将调度信息持久化到数据库。
配置 JDBCJobStore
- 准备 Quartz 官方提供的数据库建表脚本(通常位于 Quartz 发行版的
docs/dbTables目录下,选择对应数据库脚本执行)。 - 配置
quartz.properties:
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_
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 = root
org.quartz.dataSource.myDS.password = your_password
org.quartz.dataSource.myDS.maxConnections = 5
这样,所有 Job 和 Trigger 信息都会写入数据库,应用重启后调度器会从数据库恢复之前的调度状态。
集群部署与高可用
Quartz 支持集群模式,多个节点共享一个数据库。只需配置相同的 quartz.properties 并设置集群相关选项:
org.quartz.jobStore.isClustered = true
org.quartz.scheduler.instanceId = AUTO
集群中的每个节点必须拥有唯一的 instanceId。通过数据库锁机制,集群保证同一个任务同一时间只由一个节点执行,从而实现故障转移和负载均衡。注意:所有节点需要保持时钟同步,且必须使用 JDBCJobStore。
高级特性:任务传参与监听器
传递参数给 Job
使用 JobDataMap 可以在定义 JobDetail 时传入参数,在 execute 方法中获取。
JobDetail job = JobBuilder.newJob(MyJob.class)
.usingJobData("url", "https://example.com")
.usingJobData("count", 10)
.build();
// 在 execute 方法中获取
public void execute(JobExecutionContext context) {
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String url = dataMap.getString("url");
int count = dataMap.getInt("count");
}
任务监听器(JobListener)
可以编写监听器来监听任务执行前后的生命周期事件。
public class MyJobListener implements JobListener {
@Override
public String getName() { return "myListener"; }
@Override
public void jobToBeExecuted(JobExecutionContext context) {
System.out.println("任务即将执行: " + context.getJobDetail().getKey());
}
@Override
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
System.out.println("任务执行完毕");
}
}
注册监听器到调度器:
scheduler.getListenerManager().addJobListener(new MyJobListener());