Java的任务调度框架之Quartz 笔记250930
一些基本用法示例
基本用法示例 1
java
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzDemo {
public static void main(String[] args) throws SchedulerException {
// 1. 创建任务
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
// 2. 创建触发器,每5秒触发一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
// 3. 创建调度器并启动
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
public static class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("任务执行时间: " + System.currentTimeMillis());
}
}
}
基本用法示例 2 使用 CRON (CronTrigger)
java
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzCronDemo {
public static void main(String[] args) throws SchedulerException {
// 1. 创建任务
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
// 2. 创建 CronTrigger,每天8点执行
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 8 * * ?"))
.build();
// 3. 创建调度器并启动
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
public static class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("定时任务执行: 每天8点");
}
}
}
基本用法示例 3
java
public class SimpleQuartzDemo {
// 1. 定义任务类
public static class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Hello Quartz! " + new Date());
}
}
public static void main(String[] args) throws SchedulerException {
// 2. 创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 3. 定义任务详情
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("helloJob", "group1")
.build();
// 4. 定义触发器 - 立即开始,每5秒执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("helloTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
// 5. 将任务和触发器注册到调度器
scheduler.scheduleJob(job, trigger);
// 6. 启动调度器
scheduler.start();
// 7. 运行一段时间后关闭
try {
Thread.sleep(30000); // 运行30秒
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.shutdown(true);
}
}
基本用法示例 4 使用 CRON (CronTrigger)
java
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class SimpleCronExample {
// 1. 定义任务:实现Job接口
public static class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 获取任务名称
String jobName = context.getJobDetail().getKey().getName();
// 格式化当前时间
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
String currentTime = dateFormat.format(Calendar.getInstance().getTime());
// 打印任务执行信息
System.out.println("任务Key: " + jobName + " 正在执行,执行时间: " + currentTime);
}
}
public static void main(String[] args) throws Exception {
// 2. 创建调度器
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 3. 创建任务详情
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1") // 设置任务名称和组
.build();
// 4. 创建Cron触发器
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1") // 设置触发器名称和组
.withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?")) // 设置Cron表达式:每10秒执行一次
.build();
// 5. 将任务和触发器注册到调度器
scheduler.scheduleJob(job, trigger);
// 6. 启动调度器
scheduler.start();
// 主线程睡眠一段时间以便观察任务执行
Thread.sleep(60000); // 运行60秒
// 关闭调度器
scheduler.shutdown(true);
}
}
基本用法示例 5
java
// 1. 创建Scheduler实例
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 2. 定义JobDetail,关联上我们实现的Job类
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "group1") // 设置名称和组
.usingJobData("key", "value") // 可选:通过JobDataMap传递参数
.build();
// 3. 定义Trigger,指定调度规则(例如:立即开始,每10秒执行一次,重复直到永远)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever())
.build();
// 4. 将JobDetail和Trigger注册给Scheduler,并启动调度器
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
// 5. 实现Job接口
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 从context中可以获取JobDetail中设置的JobDataMap等信息
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String value = dataMap.getString("key");
System.out.println("Hello, Quartz! " + value);
}
}
基本用法示例 6 使用 CRON (CronTrigger)
java
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class SimpleCronExample {
public static void main(String[] args) {
try {
// 1. 创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start(); // 启动调度器
// 2. 定义一个Job,绑定我们实现的逻辑类
JobDetail job = JobBuilder.newJob(MySimpleJob.class)
.withIdentity("mySimpleJob", "group1")
.build();
// 3. 定义触发器,并使用Cron表达式指定执行规则(此处为每5秒一次)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("mySimpleTrigger", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.build();
// 4. 将任务和触发器告知调度器
scheduler.scheduleJob(job, trigger);
// 让程序运行一段时间,例如60秒后停止
Thread.sleep(60000);
// 关闭调度器
scheduler.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
// 5. 实现Job接口,定义你的任务逻辑
public static class MySimpleJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("简易任务执行! 时间: " + new java.util.Date());
}
}
}
基本用法示例 7
java
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzExample {
public static void main(String[] args) throws SchedulerException {
// 1. 创建JobDetail,绑定自定义Job
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.withDescription("我的定时任务")
.build();
// 2. 创建触发器,每5秒执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow() // 立即开始
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever()) // 无限循环
.build();
// 3. 创建调度器并关联Job和Trigger
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(job, trigger);
// 4. 启动调度器
scheduler.start();
}
// 自定义Job
public static class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("任务执行:" + new java.util.Date());
}
}
}
基本用法示例 8 使用 CRON (CronTrigger)
java
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzCronExample {
public static void main(String[] args) throws SchedulerException {
// 1. 创建一个JobDetail,绑定我们的任务类
JobDetail job = Job = JobBuilder.newJob(MyCronJob.class)
.withIdentity("cronJob", "cronGroup")
.withDescription("使用Cron表达式的任务")
.build();
// 2. 创建Cron触发器,定义执行规则
// 这里的Cron表达式表示:每30秒执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("cronTrigger", "cronGroup")
.withSchedule(CronScheduleBuilder.cronSchedule("0/30 * * * * ?"))
.startNow() // 立即开始执行
.build();
// 3. 创建调度器并关联任务和触发器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(job, trigger);
// 4. 启动调度器
scheduler.start();
System.out.println("调度器已启动,每30秒执行一次任务...");
}
// 自定义任务类
public static class MyCronJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 任务执行的具体逻辑
System.out.println("Cron任务执行: " + new java.util.Date());
}
}
}
Quartz作业调度框架详解
1. Quartz概述与核心价值
Quartz是一个功能全面、开源的任务调度服务,可以集成到从小的单片机系统到大型的电子商务系统等各种Java应用程序中。Quartz的核心价值在于它能够让你以非常精确的时间规划来执行任务,无论是简单的固定间隔任务(如每30秒执行一次),还是复杂的基于日历的调度(如"每月最后一个工作日的上午10点"),都能轻松应对。
在实际应用中,Quartz常用于执行诸如生成日报、数据同步、系统状态检查、自动对账、日志清理等需要定时自动完成的业务逻辑。
2. 核心概念解析
理解Quartz的以下几个核心概念是掌握其使用的关键:
2.1 核心组件
组件 | 说明 | 关键点 |
---|---|---|
Job | 定义了要执行的任务内容 | 只需实现void execute(JobExecutionContext context) 方法 |
JobDetail | 为Job实例提供属性设置、标识信息 | 承载Job的静态信息,Quartz每次执行Job时都会重新创建一个Job实例 |
Trigger | 定义任务执行的时间规则 | 控制Job的执行时机 |
Scheduler | 任务调度的核心容器,将JobDetail和Trigger绑定在一起 | 负责协调Job和Trigger,是Quartz框架的核心 |
2.2 Job的生命周期与状态管理
Quartz每次执行Job时都会创建一个新的Job实例,这意味着Job实例是无状态的。如果需要在多次执行之间保持状态,可以使用以下两种方法:
@PersistJobDataAfterExecution
注解:允许在Job执行后持久化JobDataMap中的数据@DisallowConcurrentExecution
注解:防止同一Job的多个实例并发执行,避免任务重叠
java
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class StatefulJobExample implements Job {
public void execute(JobExecutionContext context) {
// 获取并更新状态数据
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
int count = dataMap.getInt("count", 0);
dataMap.put("count", count + 1);
}
}
3. 快速入门示例
下面通过一个完整的示例展示Quartz的基本使用:
3.1 添加Maven依赖
xml
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
3.2 创建Job实现类
java
public class HelloJob implements Job {
public void execute(JobExecutionContext context) {
// 从JobDataMap获取参数
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String name = dataMap.getString("name");
System.out.println("Hello, " + name + "! 当前时间: " + new Date());
}
}
3.3 配置并启动调度
java
public class QuartzExample {
public static void main(String[] args) throws SchedulerException {
// 1. 创建JobDetail
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "group1")
.usingJobData("name", "Quartz")
.build();
// 2. 创建Trigger(每5秒执行一次,无限循环)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
// 3. 创建Scheduler并调度任务
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(jobDetail, trigger);
// 4. 启动调度器
scheduler.start();
// 5. 运行一段时间后停止
try {
Thread.sleep(30000); // 运行30秒
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.shutdown(true); // true表示等待所有正在执行的任务完成
}
}
4. Trigger类型详解
Trigger是定义任务执行时间规则的核心组件,Quartz提供了多种Trigger类型:
4.1 SimpleTrigger 适合简单的重复模式,如"每隔X时间单位执行一次,共执行Y次":
java
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("simpleTrigger", "group1")
.startAt(startTime) // 开始时间
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMinutes(5) // 每5分钟
.withRepeatCount(10)) // 重复10次(共执行11次)
.build();
4.2 CronTrigger 使用Cron表达式实现复杂的时间调度,功能最为强大:
java
// 每天上午9:15执行
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("cronTrigger", "group1")
.withCronSchedule("0 15 9 * * ?")
.build();
下面是Cron表达式的字段说明:
字段 | 允许值 | 特殊字符 |
---|---|---|
秒 | 0-59 | , - * / |
分 | 0-59 | , - * / |
小时 | 0-23 | , - * / |
日 | 1-31 | , - * ? / L W C |
月 | 1-12或JAN-DEC | , - * / |
星期 | 1-7或SUN-SAT | , - * ? / L C # |
年(可选) | 1970-2099 | , - * / |
常用Cron表达式示例:
"0 0 12 * * ?"
- 每天中午12点执行"0 15 10 * * ?"
- 每天上午10:15执行"0 0/5 14 * * ?"
- 每天下午2点到2:55期间的每5分钟执行"0 0 9 ? * MON-FRI"
- 周一至周五上午9点执行
5. 持久化与集群配置
对于生产环境,通常需要将任务配置持久化到数据库并支持集群部署。
5.1 数据库持久化配置
-
创建数据库表 :从Quartz官方发布包中获取对应的SQL脚本(路径通常为
/src/org/quartz/impl/jdbcjobstore/
),在数据库中执行创建表。 -
配置quartz.properties:
properties
# 调度器配置
org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
# 线程池配置
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 20
org.quartz.threadPool.threadPriority = 5
# 作业存储配置
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
# 数据源配置
org.quartz.jobStore.dataSource = myDS
org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password = password
5.2 集群优势
- 高可用性:一个节点故障时,其他节点可以接管任务
- 负载均衡:任务可以分散到集群中的多个节点执行
- 状态维护:通过数据库持久化保持任务状态的一致性
6. 与Spring框架集成
在实际项目中,Quartz通常与Spring框架集成使用:
6.1 Spring配置示例
xml
<bean id="myJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.example.MySpringJob"/>
<property name="durability" value="true"/>
</bean>
<bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="myJob"/>
<property name="cronExpression" value="0 0 6 * * ?"/>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="myTrigger"/>
</list>
</property>
<property name="dataSource" ref="dataSource"/>
<property name="quartzProperties">
<props>
<prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
</props>
</property>
</bean>
7. 最佳实践与常见问题
7.1 任务设计原则
- 任务幂等性:确保同一任务多次执行结果一致,防止重复执行导致问题
- 异常处理:在Job内部妥善处理异常,避免任务异常导致调度器停止工作
- 执行时间控制:避免单个任务执行时间过长,影响其他任务调度
7.2 性能优化建议
- 合理配置线程池大小:根据任务数量和特性调整线程数
- 选择合适的JobStore:小型应用可使用RAMJobStore,生产环境建议使用JDBCJobStore
- 简化JobDataMap:避免在JobDataMap中存储大量数据
7.3 常见问题排查
- 任务未按预期执行:检查Cron表达式是否正确,时区设置是否合理
- 集群环境下任务重复执行:检查数据库连接和实例ID配置
- 内存泄漏:确保不再需要的任务被正确删除和清理
Quartz作为一个成熟稳定的任务调度框架,在企业级应用中有着广泛的使用。通过合理配置和遵循最佳实践,你可以构建出可靠、高效的任务调度系统。
Java Quartz框架全面详解
Java Quartz框架全面详解
1. Quartz框架概述
1.1 什么是Quartz? Quartz是一个功能丰富的开源作业调度库,完全由Java编写,可以集成到任何Java应用程序中。它提供了强大而灵活的任务调度能力,从小型应用到大型企业级系统都能胜任。
1.2 核心特性
- 精确调度:支持秒级精度的任务调度
- 持久化:可将任务配置存储到数据库
- 集群支持:支持分布式环境下的任务调度
- 事务支持:与J2EE容器的事务集成
- 灵活触发:支持多种触发策略
- 监听机制:提供完整的事件监听体系
2. 核心架构与组件
2.1 Quartz架构图
scss
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Scheduler │───▶│ JobDetail │───▶│ Job │
│ (调度器) │ │ (任务详情) │ │ (任务逻辑) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Trigger │ │ JobDataMap │
│ (触发器) │ │ (任务数据映射) │
└─────────────────┘ └─────────────────┘
2.2 核心组件详解
Scheduler(调度器) 调度器的核心接口,负责管理任务和触发器。
java
public interface Scheduler {
// 调度任务
void scheduleJob(JobDetail jobDetail, Trigger trigger);
// 启动调度器
void start();
// 暂停调度器
void standby();
// 关闭调度器
void shutdown();
// 删除任务
boolean deleteJob(JobKey jobKey);
}
JobDetail(任务详情) 定义任务的静态信息,每次任务执行时都会基于JobDetail创建新的Job实例。
java
// 创建JobDetail的典型方式
JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity("job1", "group1")
.usingJobData("jobSays", "Hello World!")
.usingJobData("myFloatValue", 3.141f)
.build();
Job(任务接口) 业务逻辑的实现接口。
java
public interface Job {
void execute(JobExecutionContext context) throws JobExecutionException;
}
// 具体实现示例
public class MyJob implements Job {
public void execute(JobExecutionContext context) {
JobKey key = context.getJobDetail().getKey();
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
System.out.println("Instance " + key + " of MyJob says: " + jobSays + ", and val is: " + myFloatValue);
}
}
Trigger(触发器) 控制任务执行的时间规则。
java
// 触发器构建器模式
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(40)
.repeatForever())
.build();
3. 触发器(Trigger)深度解析
3.1 SimpleTrigger 适用于简单的时间间隔调度。
java
// 立即开始执行,每10秒执行一次,总共执行5次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger3", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.withRepeatCount(4)) // 注意:重复4次,总共执行5次
.build();
// 在特定时间开始,每5分钟执行一次,无限制重复
Trigger trigger2 = TriggerBuilder.newTrigger()
.withIdentity("trigger4", "group1")
.startAt(DateBuilder.dateOf(9, 0, 0)) // 当天9点开始
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMinutes(5)
.repeatForever())
.build();
3.2 CronTrigger 基于Unix cron表达式的强大触发器。
Cron表达式格式
css
秒 分 时 日 月 星期 [年]
常用Cron表达式示例
java
// 每天上午9点执行
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger5", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 9 * * ?"))
.build();
// 周一至周五上午9:30执行
Trigger trigger6 = TriggerBuilder.newTrigger()
.withIdentity("trigger6", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 30 9 ? * MON-FRI"))
.build();
// 每月最后一天下午5点执行
Trigger trigger7 = TriggerBuilder.newTrigger()
.withIdentity("trigger7", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 17 L * ?"))
.build();
Cron表达式特殊字符
字符 | 含义 | 示例 |
---|---|---|
* |
所有值 | * 在分字段表示每分钟 |
? |
不指定值 | 用于日和星期字段冲突时 |
- |
范围 | MON-FRI 表示周一到周五 |
, |
列举值 | MON,WED,FRI 表示周一、三、五 |
/ |
增量 | 0/15 在分字段表示从0分开始每15分钟 |
L |
最后 | L 在日字段表示最后一天 |
W |
工作日 | 15W 表示最接近15日的工作日 |
3.3 CalendarIntervalTrigger 基于日历间隔的触发器,能正确处理时区和夏令时。
java
// 每2周执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger8", "group1")
.startNow()
.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
.withIntervalInWeeks(2))
.build();
4. 任务状态管理与并发控制
4.1 有状态任务(Stateful Jobs) 使用注解控制任务状态。
java
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class ColorJob implements Job {
private static final String FAVORITE_COLOR = "favoriteColor";
private static final String EXECUTION_COUNT = "executionCount";
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap data = context.getJobDetail().getJobDataMap();
int count = data.getInt(EXECUTION_COUNT);
count++;
data.put(EXECUTION_COUNT, count);
String favoriteColor = data.getString(FAVORITE_COLOR);
System.out.println("ColorJob: " + context.getJobDetail().getKey() +
" executing at " + new Date() + "\n" +
" favorite color is " + favoriteColor + "\n" +
" execution count (from job map) is " + count);
}
}
4.2 注解说明
- @DisallowConcurrentExecution:防止同一JobDetail的多个实例并发执行
- @PersistJobDataAfterExecution:在Job执行后更新JobDataMap
5. 监听器(Listener)机制
5.1 JobListener 监听Job相关事件。
java
public class MyJobListener implements JobListener {
public String getName() {
return "MyJobListener";
}
// Job将要执行时调用
public void jobToBeExecuted(JobExecutionContext context) {
System.out.println("Job " + context.getJobDetail().getKey() + " is about to be executed");
}
// Job执行被否决时调用
public void jobExecutionVetoed(JobExecutionContext context) {
System.out.println("Job " + context.getJobDetail().getKey() + " execution was vetoed");
}
// Job执行完成后调用
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
System.out.println("Job " + context.getJobDetail().getKey() + " was executed");
if (jobException != null) {
System.out.println("Exception thrown by job: " + jobException.getMessage());
}
}
}
// 注册监听器
scheduler.getListenerManager().addJobListener(new MyJobListener());
5.2 TriggerListener 监听Trigger相关事件。
java
public class MyTriggerListener implements TriggerListener {
public String getName() {
return "MyTriggerListener";
}
public void triggerFired(Trigger trigger, JobExecutionContext context) {
System.out.println("Trigger " + trigger.getKey() + " fired");
}
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
// 返回true将阻止Job执行
return false;
}
public void triggerMisfired(Trigger trigger) {
System.out.println("Trigger " + trigger.getKey() + " misfired");
}
public void triggerComplete(Trigger trigger, JobExecutionContext context,
Trigger.CompletedExecutionInstruction triggerInstructionCode) {
System.out.println("Trigger " + trigger.getKey() + " completed");
}
}
6. 持久化配置
6.1 数据库表结构 Quartz需要以下核心表:
QRTZ_JOB_DETAILS
- 任务详情QRTZ_TRIGGERS
- 触发器信息QRTZ_SIMPLE_TRIGGERS
- 简单触发器QRTZ_CRON_TRIGGERS
- Cron触发器QRTZ_SCHEDULER_STATE
- 调度器状态QRTZ_FIRED_TRIGGERS
- 正在执行的触发器
6.2 持久化配置示例
properties
# quartz.properties
org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
# 线程池配置
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5
# JobStore配置
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
# 集群配置
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
# 数据源配置
org.quartz.dataSource.myDS.driver = com.mysql.cj.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password = password
org.quartz.dataSource.myDS.maxConnections = 10
7. 集群配置与故障转移
7.1 集群优势
- 高可用性:节点故障自动转移
- 负载均衡:任务在集群中均匀分布
- 故障恢复:失败的任务可以重新执行
7.2 集群配置要点
properties
# 启用集群
org.quartz.jobStore.isClustered = true
# 集群节点检查间隔(毫秒)
org.quartz.jobStore.clusterCheckinInterval = 20000
# 设置实例ID为自动生成
org.quartz.scheduler.instanceId = AUTO
8. 与Spring框架集成
8.1 Spring配置示例
xml
<!-- 配置Job -->
<bean id="myJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.example.MySpringJob"/>
<property name="durability" value="true"/>
</bean>
<!-- 配置Trigger -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="myJob"/>
<property name="cronExpression" value="0/5 * * * * ?"/>
</bean>
<!-- 配置Scheduler -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
</list>
</property>
<property name="dataSource" ref="dataSource"/>
<property name="quartzProperties">
<props>
<prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
<prop key="org.quartz.jobStore.isClustered">true</prop>
</props>
</property>
</bean>
8.2 使用Spring的MethodInvokingJobDetailFactoryBean
xml
<bean id="myService" class="com.example.MyService"/>
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myService"/>
<property name="targetMethod" value="doTask"/>
<property name="concurrent" value="false"/>
</bean>
9. 高级特性与最佳实践
9.1 错过触发处理(Misfire Instructions) 当触发器错过触发时间时的处理策略。
java
// SimpleTrigger的错过触发策略
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger9", "group1")
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMinutes(5)
.repeatForever()
.withMisfireHandlingInstructionNextWithExistingCount())
.build();
// CronTrigger的错过触发策略
Trigger trigger10 = TriggerBuilder.newTrigger()
.withIdentity("trigger10", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?")
.withMisfireHandlingInstructionDoNothing())
.build();
9.2 最佳实践
-
任务设计原则
- 保持任务简短且幂等
- 合理处理异常
- 避免在JobDataMap中存储大对象
-
性能优化
- 合理设置线程池大小
- 选择合适的持久化策略
- 定期清理已完成的任务
-
监控与管理
- 实现监控接口跟踪任务执行
- 使用JMX进行运行时管理
- 记录详细的任务执行日志
9.3 常见问题排查
java
// 获取调度器统计信息
SchedulerMetaData metaData = scheduler.getMetaData();
System.out.println("Executed Jobs: " + metaData.getNumberOfJobsExecuted());
System.out.println("Running Since: " + metaData.getRunningSince());
// 检查任务状态
List<JobExecutionContext> currentlyExecutingJobs = scheduler.getCurrentlyExecutingJobs();
for (JobExecutionContext jobCtx : currentlyExecutingJobs) {
System.out.println("Currently executing: " + jobCtx.getJobDetail().getKey());
}
Quartz作为一个成熟的企业级任务调度框架,通过合理的配置和使用,可以构建出稳定可靠的定时任务系统。掌握其核心概念和高级特性,能够帮助开发者在实际项目中更好地运用这一强大工具。
Quartz框架用法示例
Quartz框架用法完整示例
1. 基础环境搭建
1.1 Maven依赖配置
xml
<dependencies>
<!-- Quartz核心依赖 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<!-- Quartz依赖的slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>
<!-- 如果需要数据库持久化 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
</dependencies>
2. 基础用法示例
2.1 最简单的任务调度
java
public class SimpleQuartzDemo {
// 1. 定义任务类
public static class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Hello Quartz! " + new Date());
}
}
public static void main(String[] args) throws SchedulerException {
// 2. 创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 3. 定义任务详情
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("helloJob", "group1")
.build();
// 4. 定义触发器 - 立即开始,每5秒执行一次
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("helloTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
// 5. 将任务和触发器注册到调度器
scheduler.scheduleJob(job, trigger);
// 6. 启动调度器
scheduler.start();
// 7. 运行一段时间后关闭
try {
Thread.sleep(30000); // 运行30秒
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.shutdown(true);
}
}
2.2 带参数传递的任务
java
public class ParameterQuartzDemo {
public static class DataProcessJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 从JobDetail获取参数
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
String fileName = jobDataMap.getString("fileName");
int retryCount = jobDataMap.getInt("retryCount");
// 从Trigger获取参数
JobDataMap triggerDataMap = context.getTrigger().getJobDataMap();
String triggerName = triggerDataMap.getString("triggerName");
System.out.printf("处理文件: %s, 重试次数: %d, 触发器: %s, 时间: %s%n",
fileName, retryCount, triggerName, new Date());
// 更新参数(需要在Job类上添加@PersistJobDataAfterExecution注解)
jobDataMap.put("retryCount", retryCount + 1);
}
}
public static void main(String[] args) throws SchedulerException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 创建带参数的任务
JobDetail job = JobBuilder.newJob(DataProcessJob.class)
.withIdentity("dataJob", "group1")
.usingJobData("fileName", "data.txt")
.usingJobData("retryCount", 0)
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("dataTrigger", "group1")
.usingJobData("triggerName", "每日数据处理触发器")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.withRepeatCount(5)) // 执行6次后停止
.build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
// 等待任务执行完成
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.shutdown();
}
}
3. 复杂调度场景示例
3.1 Cron表达式调度
java
public class CronQuartzDemo {
public static class ReportJob implements Job {
@Override
public void execute(JobExecutionContext context) {
JobDataMap dataMap = context.getMergedJobDataMap();
String reportType = dataMap.getString("reportType");
System.out.printf("生成%s报表 - %s%n", reportType, new Date());
// 模拟报表生成业务逻辑
try {
Thread.sleep(2000); // 模拟耗时操作
System.out.printf("%s报表生成完成%n", reportType);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws SchedulerException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 每日报表任务 - 每天9点执行
JobDetail dailyJob = JobBuilder.newJob(ReportJob.class)
.withIdentity("dailyReport", "reports")
.usingJobData("reportType", "每日")
.build();
Trigger dailyTrigger = TriggerBuilder.newTrigger()
.withIdentity("dailyTrigger", "reports")
.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(9, 0)) // 每天9点
.build();
// 周报表任务 - 每周一10点执行
JobDetail weeklyJob = JobBuilder.newJob(ReportJob.class)
.withIdentity("weeklyReport", "reports")
.usingJobData("reportType", "每周")
.build();
Trigger weeklyTrigger = TriggerBuilder.newTrigger()
.withIdentity("weeklyTrigger", "reports")
.withSchedule(CronScheduleBuilder.weeklyOnDayAndHourAndMinute(
DateBuilder.MONDAY, 10, 0)) // 每周一10点
.build();
// 月报表任务 - 每月1号8点执行
JobDetail monthlyJob = JobBuilder.newJob(ReportJob.class)
.withIdentity("monthlyReport", "reports")
.usingJobData("reportType", "每月")
.build();
Trigger monthlyTrigger = TriggerBuilder.newTrigger()
.withIdentity("monthlyTrigger", "reports")
.withSchedule(CronScheduleBuilder.monthlyOnDayAndHourAndMinute(
1, 8, 0)) // 每月1号8点
.build();
// 注册所有任务
scheduler.scheduleJob(dailyJob, dailyTrigger);
scheduler.scheduleJob(weeklyJob, weeklyTrigger);
scheduler.scheduleJob(monthlyJob, monthlyTrigger);
scheduler.start();
// 显示即将执行的任务
System.out.println("已注册的触发器:");
for (String groupName : scheduler.getTriggerGroupNames()) {
for (TriggerKey triggerKey : scheduler.getTriggerKeys(GroupMatcher.groupEquals(groupName))) {
Trigger trigger = scheduler.getTrigger(triggerKey);
Date nextFireTime = trigger.getNextFireTime();
System.out.printf("触发器: %s, 下次执行时间: %s%n",
triggerKey.getName(), nextFireTime);
}
}
}
}
3.2 有状态任务控制
java
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class StatefulQuartzDemo {
public static class OrderSyncJob implements Job {
private static final String SYNC_COUNT = "syncCount";
private static final String LAST_SYNC_TIME = "lastSyncTime";
@Override
public void execute(JobExecutionContext context) {
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
int count = dataMap.getInt(SYNC_COUNT);
Date lastTime = (Date) dataMap.get(LAST_SYNC_TIME);
System.out.printf("第%d次同步订单数据, 上次同步时间: %s%n",
count + 1, lastTime);
// 模拟同步业务逻辑
try {
Thread.sleep(3000);
System.out.println("订单数据同步完成");
// 更新状态
dataMap.put(SYNC_COUNT, count + 1);
dataMap.put(LAST_SYNC_TIME, new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws SchedulerException, InterruptedException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDetail job = JobBuilder.newJob(OrderSyncJob.class)
.withIdentity("orderSyncJob", "syncGroup")
.usingJobData("syncCount", 0)
.usingJobData("lastSyncTime", new Date())
.build();
// 每10秒执行一次,但由于任务执行需要3秒,且加了@DisallowConcurrentExecution,
// 所以实际执行间隔会是10秒(而不是7秒)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("orderSyncTrigger", "syncGroup")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever())
.build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
// 运行2分钟
Thread.sleep(120000);
scheduler.shutdown(true);
}
}
4. 监听器使用示例
4.1 完整的监听器实现
java
public class ListenerQuartzDemo {
public static class EmailJob implements Job {
@Override
public void execute(JobExecutionContext context) {
JobDataMap dataMap = context.getMergedJobDataMap();
String emailContent = dataMap.getString("content");
System.out.printf("发送邮件: %s - %s%n", emailContent, new Date());
// 模拟邮件发送
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 任务监听器
public static class CustomJobListener implements JobListener {
@Override
public String getName() {
return "CustomJobListener";
}
@Override
public void jobToBeExecuted(JobExecutionContext context) {
System.out.printf(">>> 任务 %s 即将执行%n",
context.getJobDetail().getKey().getName());
}
@Override
public void jobExecutionVetoed(JobExecutionContext context) {
System.out.printf(">>> 任务 %s 执行被否决%n",
context.getJobDetail().getKey().getName());
}
@Override
public void jobWasExecuted(JobExecutionContext context,
JobExecutionException jobException) {
System.out.printf(">>> 任务 %s 执行完成",
context.getJobDetail().getKey().getName());
if (jobException != null) {
System.out.printf(", 异常: %s%n", jobException.getMessage());
} else {
System.out.println(", 执行成功");
}
}
}
// 触发器监听器
public static class CustomTriggerListener implements TriggerListener {
@Override
public String getName() {
return "CustomTriggerListener";
}
@Override
public void triggerFired(Trigger trigger, JobExecutionContext context) {
System.out.printf(">>> 触发器 %s 已触发%n", trigger.getKey().getName());
}
@Override
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
// 这里可以添加业务逻辑来决定是否阻止任务执行
// 例如:检查系统资源、业务条件等
return false; // 返回true将阻止任务执行
}
@Override
public void triggerMisfired(Trigger trigger) {
System.out.printf(">>> 触发器 %s 错过触发%n", trigger.getKey().getName());
}
@Override
public void triggerComplete(Trigger trigger, JobExecutionContext context,
Trigger.CompletedExecutionInstruction triggerInstructionCode) {
System.out.printf(">>> 触发器 %s 执行完成%n", trigger.getKey().getName());
}
}
public static void main(String[] args) throws SchedulerException, InterruptedException {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 注册全局监听器
scheduler.getListenerManager().addJobListener(new CustomJobListener());
scheduler.getListenerManager().addTriggerListener(new CustomTriggerListener());
JobDetail job = JobBuilder.newJob(EmailJob.class)
.withIdentity("emailJob", "notification")
.usingJobData("content", "这是一封测试邮件")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("emailTrigger", "notification")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(15)
.withRepeatCount(3))
.build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
Thread.sleep(60000);
scheduler.shutdown(true);
}
}
5. 数据库持久化示例
5.1 数据库配置 首先创建Quartz需要的数据库表(MySQL示例):
sql
-- 从Quartz发行包的docs/dbTables目录获取完整的SQL脚本
-- 这里简要列出主要表
CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
-- 其他表:QRTZ_TRIGGERS, QRTZ_SIMPLE_TRIGGERS, QRTZ_CRON_TRIGGERS等
5.2 持久化配置示例
java
public class PersistentQuartzDemo {
public static class BackupJob implements Job {
@Override
public void execute(JobExecutionContext context) {
System.out.println("执行数据库备份任务: " + new Date());
// 模拟备份操作
try {
Thread.sleep(5000);
System.out.println("备份完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws SchedulerException {
// 创建配置工厂
StdSchedulerFactory factory = new StdSchedulerFactory();
// 配置属性
Properties props = new Properties();
props.put("org.quartz.scheduler.instanceName", "MyPersistentScheduler");
props.put("org.quartz.scheduler.instanceId", "AUTO");
// 线程池配置
props.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
props.put("org.quartz.threadPool.threadCount", "10");
props.put("org.quartz.threadPool.threadPriority", "5");
// JobStore配置 - 使用JDBC存储
props.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
props.put("org.quartz.jobStore.driverDelegateClass",
"org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
props.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
props.put("org.quartz.jobStore.dataSource", "myDS");
// 数据源配置
props.put("org.quartz.dataSource.myDS.driver", "com.mysql.cj.jdbc.Driver");
props.put("org.quartz.dataSource.myDS.URL",
"jdbc:mysql://localhost:3306/quartz_demo?useSSL=false");
props.put("org.quartz.dataSource.myDS.user", "root");
props.put("org.quartz.dataSource.myDS.password", "password");
props.put("org.quartz.dataSource.myDS.maxConnections", "10");
try {
factory.initialize(props);
Scheduler scheduler = factory.getScheduler();
// 创建持久化任务
JobDetail job = JobBuilder.newJob(BackupJob.class)
.withIdentity("backupJob", "system")
.storeDurably() // 设置任务为持久化
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("backupTrigger", "system")
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/30 * * * ?")) // 每30分钟
.build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
System.out.println("持久化任务已启动,任务信息已保存到数据库");
System.out.println("即使程序重启,任务也会继续执行");
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
6. Spring集成示例
6.1 Spring配置方式
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 业务Bean -->
<bean id="userService" class="com.example.UserService"/>
<!-- 方法调用Job -->
<bean id="userCleanupJob"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="userService"/>
<property name="targetMethod" value="cleanupInactiveUsers"/>
<property name="concurrent" value="false"/> <!-- 禁止并发 -->
</bean>
<!-- 触发器 -->
<bean id="userCleanupTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="userCleanupJob"/>
<property name="cronExpression" value="0 0 2 * * ?"/> <!-- 每天凌晨2点 -->
</bean>
<!-- 调度器 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="userCleanupTrigger"/>
</list>
</property>
<property name="quartzProperties">
<props>
<prop key="org.quartz.threadPool.threadCount">5</prop>
</props>
</property>
</bean>
</beans>
6.2 注解配置方式
java
@Configuration
public class QuartzSpringConfig {
@Bean
public UserService userService() {
return new UserService();
}
@Bean
public JobDetailFactoryBean userSyncJobDetail() {
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(UserSyncJob.class);
factoryBean.setDurability(true);
factoryBean.setJobDataAsMap(new HashMap<String, Object>() {{
put("batchSize", 100);
}});
return factoryBean;
}
@Bean
public CronTriggerFactoryBean userSyncTrigger(JobDetail userSyncJobDetail) {
CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
factoryBean.setJobDetail(userSyncJobDetail);
factoryBean.setCronExpression("0 0/5 * * * ?"); // 每5分钟
return factoryBean;
}
@Bean
public SchedulerFactoryBean scheduler(Trigger userSyncTrigger) {
SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
factoryBean.setTriggers(userSyncTrigger);
Properties quartzProperties = new Properties();
quartzProperties.setProperty("org.quartz.threadPool.threadCount", "3");
factoryBean.setQuartzProperties(quartzProperties);
return factoryBean;
}
}
7. 实用工具类示例
7.1 Quartz管理工具类
java
public class QuartzManager {
private Scheduler scheduler;
public QuartzManager() throws SchedulerException {
this.scheduler = StdSchedulerFactory.getDefaultScheduler();
}
/**
* 添加Cron任务
*/
public void addCronJob(String jobName, String jobGroup,
Class<? extends Job> jobClass,
String cronExpression,
Map<String, Object> jobData) throws SchedulerException {
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobName, jobGroup)
.build();
if (jobData != null) {
jobDetail.getJobDataMap().putAll(jobData);
}
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobName + "Trigger", jobGroup)
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.build();
scheduler.scheduleJob(jobDetail, trigger);
}
/**
* 暂停任务
*/
public void pauseJob(String jobName, String jobGroup) throws SchedulerException {
scheduler.pauseJob(JobKey.jobKey(jobName, jobGroup));
}
/**
* 恢复任务
*/
public void resumeJob(String jobName, String jobGroup) throws SchedulerException {
scheduler.resumeJob(JobKey.jobKey(jobName, jobGroup));
}
/**
* 删除任务
*/
public boolean deleteJob(String jobName, String jobGroup) throws SchedulerException {
return scheduler.deleteJob(JobKey.jobKey(jobName, jobGroup));
}
/**
* 立即执行一次任务
*/
public void triggerJob(String jobName, String jobGroup) throws SchedulerException {
scheduler.triggerJob(JobKey.jobKey(jobName, jobGroup));
}
/**
* 获取所有任务
*/
public List<String> getAllJobs() throws SchedulerException {
List<String> jobList = new ArrayList<>();
for (String groupName : scheduler.getJobGroupNames()) {
for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
jobList.add(groupName + "." + jobKey.getName());
}
}
return jobList;
}
/**
* 启动调度器
*/
public void start() throws SchedulerException {
if (!scheduler.isStarted()) {
scheduler.start();
}
}
/**
* 关闭调度器
*/
public void shutdown() throws SchedulerException {
scheduler.shutdown(true);
}
}
这些示例涵盖了Quartz框架的主要使用场景,从基础任务调度到高级特性如持久化、监听器、Spring集成等。根据实际需求选择合适的示例进行参考和修改。
CronTrigger ( Cron表达式格式 )
Quartz CronTrigger与Cron表达式全面详解
1. Cron表达式基础结构
1.1 标准格式 Quartz的Cron表达式由6个或7个字段组成(年字段可选),各字段用空格分隔:
css
秒 分 时 日 月 星期 [年]
1.2 字段说明表
位置 | 字段 | 允许值 | 允许的特殊字符 |
---|---|---|---|
1 | 秒 | 0-59 | , - * / |
2 | 分 | 0-59 | , - * / |
3 | 时 | 0-23 | , - * / |
4 | 日 | 1-31 | , - * ? / L W C |
5 | 月 | 1-12 或 JAN-DEC | , - * / |
6 | 星期 | 1-7 或 SUN-SAT | , - * ? / L C # |
7 | 年 (可选) | 1970-2099 | , - * / |
注意:
- 星期字段中:1=星期日, 2=星期一, ..., 7=星期六
- 日和星期字段是互斥的,通常其中一个使用
?
2. 特殊字符详解
2.1 基础特殊字符
字符 | 名称 | 说明 | 示例 |
---|---|---|---|
* |
所有值 | 匹配该字段所有有效值 | * 在分字段=每分钟 |
? |
不指定 | 用于日和星期字段避免冲突 | 0 0 0 ? * MON |
- |
范围 | 指定值的范围 | MON-FRI =周一到周五 |
, |
列举 | 指定多个值 | MON,WED,FRI =周一三五 |
/ |
增量 | 指定起始值和间隔 | 0/15 =从0开始每15单位 |
2.2 高级特殊字符
字符 | 名称 | 说明 | 示例 |
---|---|---|---|
L |
最后 | 月份或星期的最后一天 | L 在日字段=月底 |
W |
工作日 | 最近的工作日 | 15W =最接近15日的工作日 |
# |
第几个 | 月份中第几个星期几 | MON#2 =第2个星期一 |
C |
日历 | 日历计算(较少使用) | C 在日字段=日历日后的第一天 |
3. 完整代码示例
3.1 各种Cron表达式示例
java
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.Date;
public class CronTriggerDetailedExample {
public static class DemoJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap dataMap = context.getMergedJobDataMap();
String description = dataMap.getString("description");
System.out.println("[" + new Date() + "] " + description);
}
}
public static void main(String[] args) throws Exception {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
// 示例1: 基础间隔 - 每30秒执行
scheduleJob(scheduler, "job1", "每30秒执行", "0/30 * * * * ?");
// 示例2: 固定时间 - 每天12:30执行
scheduleJob(scheduler, "job2", "每天12:30执行", "0 30 12 * * ?");
// 示例3: 工作日调度 - 周一至周五9点到17点每小时执行
scheduleJob(scheduler, "job3", "工作日9-17点每小时执行", "0 0 9-17 ? * MON-FRI");
// 示例4: 复杂组合 - 每月第1天和第15天的10:15执行
scheduleJob(scheduler, "job4", "每月1号和15号10:15执行", "0 15 10 1,15 * ?");
// 示例5: 使用L(最后) - 每月最后一天23:59执行
scheduleJob(scheduler, "job5", "每月最后一天23:59执行", "0 59 23 L * ?");
// 示例6: 使用W(工作日) - 最接近15号的工作日9点执行
scheduleJob(scheduler, "job6", "最接近15号的工作日9点执行", "0 0 9 15W * ?");
// 示例7: 使用#(第几个) - 每月第2个周一8:30执行
scheduleJob(scheduler, "job7", "每月第2个周一8:30执行", "0 30 8 ? * 2#2");
// 示例8: 使用/增量 - 从5分开始每20分钟执行
scheduleJob(scheduler, "job8", "每小时的5,25,45分执行", "0 5/20 * * * ?");
// 示例9: 包含年份 - 2024年每天执行
scheduleJob(scheduler, "job9", "2024年每天12点执行", "0 0 12 * * ? 2024");
// 运行5分钟后关闭
Thread.sleep(300000);
scheduler.shutdown(true);
}
private static void scheduleJob(Scheduler scheduler, String jobName,
String description, String cronExpression)
throws SchedulerException {
JobDetail job = JobBuilder.newJob(DemoJob.class)
.withIdentity(jobName, "cron-group")
.usingJobData("description", description + " - " + cronExpression)
.build();
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobName + "-trigger", "cron-group")
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.build();
scheduler.scheduleJob(job, trigger);
System.out.println("已调度: " + description);
}
}
3.2 高级CronTrigger配置
java
public class AdvancedCronTriggerExample {
public static void main(String[] args) throws Exception {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDetail job = JobBuilder.newJob(DemoJob.class)
.withIdentity("advancedJob", "group1")
.usingJobData("description", "高级CronTrigger示例")
.build();
// 创建带有高级配置的CronTrigger
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("advancedTrigger", "group1")
.withDescription("这是一个带有高级配置的触发器")
// Cron表达式:工作日每15分钟执行
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/15 * ? * MON-FRI")
// 设置时区
.inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))
// 错过触发处理策略
.withMisfireHandlingInstructionDoNothing()
)
// 开始时间
.startAt(DateBuilder.todayAt(9, 0, 0)) // 今天9点开始
// 结束时间
.endAt(DateBuilder.dateOf(17, 0, 0)) // 今天17点结束
// 优先级(默认5)
.withPriority(7)
.build();
scheduler.scheduleJob(job, trigger);
// 获取触发器信息
System.out.println("下次触发时间: " + trigger.getNextFireTime());
System.out.println("最终触发时间: " + trigger.getFinalFireTime());
System.out.println("Cron表达式: " + trigger.getCronExpression());
Thread.sleep(60000);
scheduler.shutdown(true);
}
}
4. 实用Cron表达式参考手册
4.1 常用表达式速查
场景 | Cron表达式 | 说明 |
---|---|---|
每秒执行 | * * * * * ? |
每秒执行一次 |
每5秒 | 0/5 * * * * ? |
从0秒开始每5秒 |
每30分钟 | 0 0/30 * * * ? |
每30分钟执行 |
整点执行 | 0 0 * * * ? |
每小时0分0秒 |
每天固定时间 | 0 0 12 * * ? |
每天12:00执行 |
工作日执行 | 0 0 9 ? * MON-FRI |
工作日9:00执行 |
周末执行 | 0 0 10 ? * SAT,SUN |
周末10:00执行 |
每月1号 | 0 0 6 1 * ? |
每月1号6:00执行 |
每月最后一天 | 0 0 18 L * ? |
每月最后一天18:00 |
季度执行 | 0 0 8 1 1,4,7,10 ? |
每季度第一天8:00 |
4.2 复杂业务场景
java
public class BusinessCronExamples {
// 银行对账场景:工作日17:30执行
public static final String BANK_RECONCILIATION = "0 30 17 ? * MON-FRI";
// 数据备份场景:每天2:00执行
public static final String DAILY_BACKUP = "0 0 2 * * ?";
// 周报生成:每周一9:00执行
public static final String WEEKLY_REPORT = "0 0 9 ? * MON";
// 月报生成:每月1号10:00执行
public static final String MONTHLY_REPORT = "0 0 10 1 * ?";
// 促销活动:特定时间段执行
public static final String PROMOTION_JOB = "0 0 9,14,19 * * ?";
// 监控任务:工作时间每5分钟执行
public static final String MONITORING = "0 0/5 9-18 ? * MON-FRI";
}
5. Cron表达式验证与调试
5.1 表达式验证工具类
java
import org.quartz.CronExpression;
import java.text.ParseException;
import java.util.Date;
public class CronValidator {
/**
* 验证Cron表达式是否有效
*/
public static boolean isValidCronExpression(String cronExpression) {
return CronExpression.isValidExpression(cronExpression);
}
/**
* 获取接下来几次执行时间
*/
public static void printNextFireTimes(String cronExpression, int count) {
try {
CronExpression cron = new CronExpression(cronExpression);
Date now = new Date();
System.out.println("Cron表达式: " + cronExpression);
System.out.println("接下来" + count + "次执行时间:");
Date nextTime = now;
for (int i = 0; i < count; i++) {
nextTime = cron.getNextValidTimeAfter(nextTime);
if (nextTime == null) {
System.out.println(" " + (i + 1) + ": 无更多执行时间");
break;
}
System.out.println(" " + (i + 1) + ": " + nextTime);
}
} catch (ParseException e) {
System.out.println("无效的Cron表达式: " + e.getMessage());
}
}
public static void main(String[] args) {
// 测试验证
String[] testExpressions = {
"0 0 12 * * ?", // 有效
"0 0 12 * * ? 2024", // 有效
"invalid-expression", // 无效
"60 * * * * ?", // 无效(秒超出范围)
};
for (String expr : testExpressions) {
System.out.println(expr + " : " +
(isValidCronExpression(expr) ? "有效" : "无效"));
}
// 查看执行时间
printNextFireTimes("0 30 9 ? * MON-FRI", 5);
}
}
6. 常见问题与解决方案
6.1 表达式调试技巧
java
public class CronDebugging {
public static void debugCronExpression(String cronExpression) {
try {
CronExpression cron = new CronExpression(cronExpression);
System.out.println("=== Cron表达式分析 ===");
System.out.println("原始表达式: " + cronExpression);
System.out.println("表达式摘要: " + cron.getExpressionSummary());
// 测试执行时间
Date baseTime = new Date();
System.out.println("基于当前时间: " + baseTime);
for (int i = 1; i <= 3; i++) {
Date nextTime = cron.getNextValidTimeAfter(baseTime);
if (nextTime != null) {
System.out.println("第" + i + "次执行: " + nextTime);
baseTime = nextTime;
} else {
System.out.println("第" + i + "次执行: 无更多执行时间");
break;
}
}
} catch (ParseException e) {
System.out.println("表达式解析错误: " + e.getMessage());
System.out.println("请检查以下常见问题:");
System.out.println("1. 字段数量是否正确(6或7个字段)");
System.out.println("2. 数值范围是否合法");
System.out.println("3. 特殊字符使用是否正确");
System.out.println("4. 日和星期字段是否冲突");
}
}
public static void main(String[] args) {
debugCronExpression("0 30 9 ? * MON-FRI");
}
}
6.2 常见错误及修正
错误表达式 | 问题 | 修正方案 |
---|---|---|
0 0 12 * * |
缺少秒字段 | 0 0 12 * * ? |
* * * * * |
缺少秒字段且日和星期冲突 | * * * * * ? |
0 60 * * * ? |
分钟值超出范围 | 0 0/59 * * * ? |
0 0 12 1 * MON |
日和星期同时指定 | 0 0 12 1 * ? 或 0 0 12 ? * MON |
0 0 12 L * SUN |
L和具体值冲突 | 0 0 12 ? * SUN |
通过这份详细的CronTrigger和Cron表达式指南,你应该能够熟练地创建各种复杂的调度任务。记住在实际项目中,合理的Cron表达式设计对于系统稳定性和性能至关重要。
Java的任务调度框架有哪些?
1. 原生Java调度方案
1.1 Timer & TimerTask
java
// 最简单的原生调度方案
public class TimerExample {
public static void main(String[] args) {
Timer timer = new Timer();
// 延迟1秒后执行,每隔2秒重复执行
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("TimerTask执行: " + new Date());
}
}, 1000, 2000);
// 运行10秒后取消
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
timer.cancel();
}
}
特点:
- JDK内置,无需额外依赖
- 单线程执行,任务会相互阻塞
- 功能简单,不支持cron表达式
- 异常处理不完善
1.2 ScheduledExecutorService
java
public class ScheduledExecutorExample {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
// 固定延迟执行
executor.scheduleWithFixedDelay(() -> {
System.out.println("固定延迟任务: " + new Date());
}, 1, 2, TimeUnit.SECONDS);
// 固定频率执行
executor.scheduleAtFixedRate(() -> {
System.out.println("固定频率任务: " + new Date());
}, 1, 3, TimeUnit.SECONDS);
// 单次执行
executor.schedule(() -> {
System.out.println("单次任务执行");
}, 5, TimeUnit.SECONDS);
}
}
特点:
- JDK 5+ 内置
- 线程池支持,避免任务阻塞
- 更灵活的调度控制
- 功能相对基础
2. 企业级调度框架
2.1 Quartz(重点)
java
// 企业级标准选择
public class QuartzAdvantages {
// 优势:
// 1. 功能全面:支持cron表达式、日历排除、错过触发处理等
// 2. 持久化:支持数据库存储任务配置
// 3. 集群:支持分布式部署和故障转移
// 4. 事务:支持JTA事务
// 5. 监听器:完整的任务生命周期监听
}
适用场景:
- 复杂的企业级调度需求
- 需要持久化和集群支持
- 高可用性要求的系统
- 复杂的调度规则(节假日排除等)
2.2 Spring Framework内置调度
2.2.1 @Scheduled注解
java
@Component
public class SpringScheduledExample {
// 固定速率执行
@Scheduled(fixedRate = 5000)
public void fixedRateTask() {
System.out.println("固定速率任务: " + new Date());
}
// 固定延迟执行
@Scheduled(fixedDelay = 3000)
public void fixedDelayTask() {
System.out.println("固定延迟任务: " + new Date());
}
// Cron表达式
@Scheduled(cron = "0 0 9 * * MON-FRI")
public void cronTask() {
System.out.println("工作日9点执行");
}
// 初始延迟
@Scheduled(initialDelay = 10000, fixedRate = 5000)
public void initialDelayTask() {
System.out.println("10秒后开始,每5秒执行");
}
}
2.2.2 配置类
java
@Configuration
@EnableScheduling
public class SchedulerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
@Bean(destroyMethod = "shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
}
特点:
- Spring生态无缝集成
- 注解驱动,配置简单
- 适合简单的定时任务需求
- 不支持持久化和集群
3. 分布式调度框架
3.1 Elastic-Job
java
// 分布式调度解决方案
public class ElasticJobExample {
// 主要特性:
// 1. 分布式协调
// 2. 弹性扩容缩容
// 3. 失效转移
// 4. 错过任务重触发
// 5. 支持作业分片
}
配置示例:
xml
<!-- Elastic-Job配置 -->
<job:simple id="myElasticJob"
class="com.example.MyElasticJob"
registry-center-ref="regCenter"
cron="0/5 * * * * ?"
sharding-total-count="3"
overwrite="true"/>
适用场景:
- 大规模分布式系统
- 需要水平扩展的调度任务
- 高可用和负载均衡需求
3.2 XXL-Job
java
// 分布式任务调度平台
@Component
public class XxlJobExample {
@XxlJob("demoJobHandler")
public ReturnT<String> demoJobHandler(String param) throws Exception {
// 任务逻辑
System.out.println("XXL-Job执行: " + param);
return ReturnT.SUCCESS;
}
@XxlJob("shardingJobHandler")
public ReturnT<String> shardingJobHandler(String param) throws Exception {
// 分片参数
ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo();
System.out.println("分片编号:" + shardingVO.getIndex() +
", 总分片数:" + shardingVO.getTotal());
return ReturnT.SUCCESS;
}
}
特点:
- 提供Web管理界面
- 支持动态调整任务参数
- 完整的执行日志和监控
- 故障报警机制
3.3 PowerJob
java
// 新一代分布式任务调度框架
@Slf4j
@Component
public class PowerJobExample {
@PowerJobHandler("powerJobDemo")
public ProcessResult powerJobDemo(TaskContext context) throws Exception {
// 获取任务参数
String jobParams = context.getJobParams();
// 处理逻辑
log.info("PowerJob执行, 参数: {}", jobParams);
// 返回结果
return new ProcessResult(true, "执行成功");
}
}
优势:
- 支持MapReduce执行模式
- 工作流支持
- 强大的可视化界面
- 容器化部署友好
4. 轻量级调度框架
4.1 JobRunr
java
// 基于后台线程的轻量级调度
public class JobRunrExample {
public static void main(String[] args) {
// 配置存储
StorageProvider storageProvider = new InMemoryStorageProvider();
// 创建后台服务
BackgroundJobServer backgroundJobServer =
new BackgroundJobServer(storageProvider);
// 调度任务
BackgroundJob.schedule(
ZonedDateTime.now().plusHours(1),
() -> System.out.println("JobRunr延迟任务")
);
// 重复任务
BackgroundJob.scheduleRecurring(
"recurring-job",
Cron.daily(),
() -> System.out.println("每日任务")
);
}
}
4.2 db-scheduler
java
// 基于数据库的轻量级调度
public class DbSchedulerExample {
public static void main(String[] args) {
// 数据源配置
DataSource dataSource = ...;
// 创建调度器
Scheduler scheduler = Scheduler.create(dataSource)
.threads(5)
.pollingInterval(Duration.ofSeconds(10))
.build();
// 定义任务
RecurringTask recurringTask = Tasks.recurring("my-recurring-task",
Schedules.fixedDelay(Duration.ofMinutes(5)))
.execute((instance, context) -> {
System.out.println("执行任务");
});
// 注册任务
scheduler.schedule(recurringTask);
// 启动调度器
scheduler.start();
}
}
5. 云原生调度方案
5.1 SchedulerX(阿里云)
java
// 阿里云调度服务
@Component
public class SchedulerXExample {
@JobProcessor("MyJobHandler")
public ProcessResult process(JobContext context) {
try {
// 任务逻辑
String parameter = context.getJobParameter();
System.out.println("处理任务: " + parameter);
return new ProcessResult(true);
} catch (Exception e) {
return new ProcessResult(false, e.getMessage());
}
}
}
5.2 Kubernetes CronJob
yaml
# K8s原生调度方案
apiVersion: batch/v1
kind: CronJob
metadata:
name: my-scheduled-job
spec:
schedule: "0 6 * * *" # 每天6点执行
jobTemplate:
spec:
template:
spec:
containers:
- name: my-job
image: my-app:latest
command: ["java", "-jar", "app.jar"]
restartPolicy: OnFailure
6. 框架对比与选型指南
6.1 功能对比矩阵
框架 | 持久化 | 集群 | 分布式 | 管理界面 | 学习曲线 | 适用规模 |
---|---|---|---|---|---|---|
Timer | ❌ | ❌ | ❌ | ❌ | 简单 | 小型 |
ScheduledExecutor | ❌ | ❌ | ❌ | ❌ | 简单 | 小型 |
Spring @Scheduled | ❌ | ❌ | ❌ | ❌ | 简单 | 中小型 |
Quartz | ✅ | ✅ | ❌ | ❌ | 中等 | 中大型 |
Elastic-Job | ✅ | ✅ | ✅ | ✅ | 较复杂 | 大型分布式 |
XXL-Job | ✅ | ✅ | ✅ | ✅ | 中等 | 大型分布式 |
PowerJob | ✅ | ✅ | ✅ | ✅ | 中等 | 云原生分布式 |
6.2 选型建议
场景1:简单单机应用
java
// 推荐:Spring @Scheduled 或 ScheduledExecutorService
@Configuration
@EnableScheduling
public class SimpleSchedulerConfig {
// 配置简单,满足基本需求
}
场景2:传统企业应用
java
// 推荐:Quartz
public class EnterpriseQuartzSetup {
// 功能全面,稳定可靠
// 支持持久化和复杂调度规则
}
场景3:微服务/分布式系统
java
// 推荐:XXL-Job 或 PowerJob
@Component
public class DistributedJobHandler {
// 支持分布式协调,有完善的管理界面
// 适合云原生环境
}
场景4:高并发互联网应用
java
// 推荐:Elastic-Job
public class InternetScaleJob {
// 支持分片和弹性扩容
// 适合海量数据处理
}
6.3 性能考量因素
- 任务数量:单机几千任务以内Quartz足够,上万任务考虑分布式方案
- 执行频率:秒级调度选择Quartz,分钟级以上各种方案均可
- 任务时长:短任务适合所有框架,长任务考虑异步和状态管理
- 可靠性要求:高可靠性需求选择支持持久化和集群的方案
6.4 发展趋势
- 云原生:Kubernetes CronJob + 自定义调度器
- Serverless:函数计算 + 事件驱动调度
- 智能化:基于机器学习的动态调度优化
- 可视化:统一的调度任务管理平台
7. 实际项目示例
7.1 中小型项目配置
java
@Configuration
public class SmallProjectScheduler {
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5);
scheduler.setThreadNamePrefix("small-project-scheduler-");
scheduler.setWaitForTasksToCompleteOnShutdown(true);
scheduler.setAwaitTerminationSeconds(60);
return scheduler;
}
@Bean
public ScheduledExecutorService backupExecutor() {
return Executors.newScheduledThreadPool(3);
}
}
7.2 大型项目架构
java
@Configuration
@EnableSchedulerX
public class LargeProjectScheduler {
@Bean
public SchedulerFactoryBean clusterQuartzScheduler(DataSource dataSource) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource);
factory.setQuartzProperties(quartzProperties());
factory.setSchedulerName("ClusterQuartzScheduler");
factory.setApplicationContextSchedulerContextKey("applicationContext");
return factory;
}
private Properties quartzProperties() {
Properties props = new Properties();
props.setProperty("org.quartz.scheduler.instanceName", "ClusterScheduler");
props.setProperty("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
props.setProperty("org.quartz.jobStore.isClustered", "true");
return props;
}
}
根据项目规模、团队技术栈和具体需求,选择合适的调度框架可以大大提高开发效率和系统稳定性。