Quartz 是一个功能强大的任务调度框架,广泛用于在 Java 应用程序中定时执行任务,同时它支持 Cron 表达式、持久化任务、集群等特性。以下是 Quartz 的详细使用教程,包括安装、基本概念、简单示例和高级功能。
1. 安装 Quartz
首先,在你的项目中添加 Quartz 依赖。对于 Maven 项目,可以在 pom.xml
中添加以下依赖:
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
对于 Gradle 项目,可以在 build.gradle
中添加以下依赖:
implementation 'org.quartz-scheduler:quartz:2.3.2'
2. 基本概念
Quartz 的核心概念包括:
- Scheduler:调度器,是 Quartz 的核心,负责管理和调度任务。
- Job:任务,是实际执行的工作单元。需要实现
Job
接口。 - JobDetail:定义任务的详细信息,包括任务的名称、组、以及任务的类。
- Trigger:触发器,定义任务何时执行。常用的触发器包括 SimpleTrigger 和 CronTrigger。
- JobStore:任务存储,定义任务的存储方式。常见的有 RAMJobStore(内存存储)和 JDBCJobStore(数据库存储)。
3. 简单示例
以下是一个简单的 Quartz 示例,展示如何创建和调度一个任务。
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! Current time: " + System.currentTimeMillis());
}
}
2. 配置 Scheduler 和 Job
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzExample {
public static void main(String[] args) throws SchedulerException {
// 创建 Scheduler 实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 定义一个 JobDetail 实例
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("helloJob", "group1")
.build();
// 创建一个触发器,每隔5秒执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("helloTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
// 调度任务
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}
4. 高级功能
1. 使用 CronTrigger
CronTrigger 允许使用 Cron 表达式来定义复杂的调度规则。
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class CronTriggerExample {
public static void main(String[] args) throws SchedulerException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("cronJob", "group1")
.build();
// 使用 Cron 表达式创建触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("cronTrigger", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?"))
.build();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}
2. Cron 表达式
Cron 表达式用于定义任务调度的时间规则。它由6或7个字段组成,字段之间用空格分隔。以下是每个字段的含义:
┌───────────── 秒 (0 - 59)
│ ┌───────────── 分 (0 - 59)
│ │ ┌───────────── 小时 (0 - 23)
│ │ │ ┌───────────── 日 (1 - 31)
│ │ │ │ ┌───────────── 月 (1 - 12)
│ │ │ │ │ ┌───────────── 星期几 (0 - 7) (0 和 7 都是星期日)
│ │ │ │ │ │
│ │ │ │ │ │
* * * * * *
2.1 特殊字符
*
: 表示任意值。?
: 仅在日和星期字段中使用,表示不指定值。-
: 表示范围,例如10-12
表示从10到12。,
: 表示列表值,例如1,2,3
表示1、2、3。/
: 表示增量,例如0/15
表示从0开始每15分钟。L
: 表示最后,例如L
在日字段表示月的最后一天。W
: 表示最近的工作日,例如15W
表示最接近15号的工作日。#
: 表示第几个星期几,例如2#1
表示第一个星期一。
2.2 示例
0 0 12 * * ?
: 每天中午12点执行。0 15 10 ? * *
: 每天上午10:15执行。0 15 10 * * ?
: 每天上午10:15执行。0 15 10 * * ? 2024
: 2024年每天上午10:15执行。0 * 14 * * ?
: 每天下午2点到2:59每分钟执行一次。0 0/5 14 * * ?
: 每天下午2点到2:55每5分钟执行一次。0 0/5 14,18 * * ?
: 每天下午2点到2:55每5分钟执行一次,以及每天下午6点到6:55每5分钟执行一次。0 0-5 14 * * ?
: 每天下午2点到2:05每分钟执行一次。0 10,44 14 ? 3 WED
: 每年三月的每个星期三下午2:10和2:44执行。
3. 使用 JobListener
JobListener 可以在任务执行的不同阶段进行拦截和处理。
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
public class MyJobListener implements JobListener {
@Override
public String getName() {
return "MyJobListener";
}
@Override
public void jobToBeExecuted(JobExecutionContext context) {
//在任务即将被执行时调用,可以在任务执行前进行一些准备工作或记录日志。
System.out.println("Job is about to be executed: " + context.getJobDetail().getKey());
}
@Override
public void jobExecutionVetoed(JobExecutionContext context) {
//在任务执行被否决时调用,当某些条件满足时,可以阻止任务的执行,并在此方法中执行相应的处理逻辑。
System.out.println("Job execution was vetoed: " + context.getJobDetail().getKey());
}
@Override
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
//在任务执行完成后调用,可以在任务执行后进行一些清理工作或记录日志。如果任务执行过程中抛出异常,jobException 将包含该异常信息。
System.out.println("Job was executed: " + context.getJobDetail().getKey())