各位被Thread.sleep()
和ScheduledExecutorService
折磨的道友们!今天要解锁的是Java界任务调度至尊法宝——Quartz!这货能让你像玉皇大帝安排天庭日程一样,精确控制每个任务的执行时机!准备好告别蹩脚的手动定时器了吗? ⏰
一、筑基篇:初识Quartz
1.1 法宝祭炼(添加依赖)
<!-- Spring Boot集成版(推荐) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!-- 原生使用版 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
1.2 核心概念三件套
- Job:要执行的任务(如:“发送仙丹提醒”)
- Trigger:触发时机(如:“每月初一子时”)
- Scheduler:调度中心(天庭的日程总管)
二、金丹篇:基础任务调度
2.1 定义Job(编写仙术)
public class SendPillJob implements Job {
@Override
public void execute(JobExecutionContext context) {
// 获取传递的参数
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String userName = dataMap.getString("user");
System.out.println(LocalDateTime.now() +
":给" + userName + "发送仙丹提醒!");
}
}
2.2 配置Trigger(天时安排)
// 简单触发器(每30秒执行一次)
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("pillTrigger")
.startNow()
.withSchedule(SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(30)
.repeatForever())
.build();
// Cron触发器(每天上午8点执行)
Trigger cronTrigger = TriggerBuilder.newTrigger()
.withIdentity("morningTrigger")
.withSchedule(CronScheduleBuilder
.dailyAtHourAndMinute(8, 0))
.build();
2.3 启动调度(开坛做法)
// 创建任务详情
JobDetail job = JobBuilder.newJob(SendPillJob.class)
.withIdentity("sendPillJob")
.usingJobData("user", "张无忌") // 传参
.build();
// 创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(job, trigger);
scheduler.start();
三、元婴篇:Spring Boot集成
3.1 自动配置(偷懒大法)
@Configuration
public class QuartzConfig {
@Bean
public JobDetail morningPillJobDetail() {
return JobBuilder.newJob(SendPillJob.class)
.withIdentity("morningPillJob")
.storeDurably()
.build();
}
@Bean
public Trigger morningPillTrigger() {
return TriggerBuilder.newTrigger()
.forJob(morningPillJobDetail())
.withIdentity("morningPillTrigger")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 8 * * ?"))
.build();
}
}
3.2 注入Service(灵力融合)
public class SendPillJob implements Job {
@Autowired // 通过SpringBeanJobFactory注入
private PillService pillService;
@Override
public void execute(JobExecutionContext context) {
pillService.sendReminder();
}
}
四、化神篇:高级特性
4.1 持久化存储(渡劫不丢数据)
# application.yml
spring:
quartz:
job-store-type: jdbc # 使用数据库存储
jdbc:
initialize-schema: always # 自动建表
properties:
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix: QRTZ_
4.2 集群模式(分身协作)
spring:
quartz:
properties:
org.quartz.jobStore.isClustered: true
org.quartz.scheduler.instanceId: AUTO # 自动生成实例ID
org.quartz.jobStore.acquireTriggersWithinLock: true
4.3 监听器(天眼通)
public class JobListener implements org.quartz.JobListener {
@Override
public String getName() { return "globalJobListener"; }
@Override
public void jobToBeExecuted(JobExecutionContext context) {
System.out.println("任务即将执行:" + context.getJobDetail().getKey());
}
}
// 注册监听器
scheduler.getListenerManager().addJobListener(new JobListener());
五、大乘篇:最佳实践
5.1 异常处理(渡劫护盾)
public class RetryJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try {
// 业务代码...
} catch (Exception e) {
// 失败后重试
JobExecutionException e2 = new JobExecutionException(e);
e2.setRefireImmediately(true);
throw e2;
}
}
}
5.2 动态调度(天机可变)
@Autowired
private Scheduler scheduler;
// 动态添加任务
public void addDynamicJob(String jobName, String cron) throws SchedulerException {
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobName + "Trigger")
.withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
JobDetail job = JobBuilder.newJob(DynamicJob.class)
.withIdentity(jobName)
.usingJobData("param", "value")
.build();
scheduler.scheduleJob(job, trigger);
}
六、渡劫警示(常见天劫)
-
时区问题
// 明确指定时区 CronScheduleBuilder.cronSchedule("0 0 12 * * ?") .inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))
-
任务阻塞
- 使用
@DisallowConcurrentExecution
禁止并发执行同一Job - 长时间任务考虑拆分
- 使用
-
内存泄漏
- 及时调用
scheduler.shutdown()
- 避免在Job中创建大量临时对象
- 及时调用
飞升指南:调度策略
场景 | 推荐Trigger | 示例 |
---|---|---|
简单定时循环 | SimpleTrigger | 每30秒执行一次 |
固定时间点 | CronTrigger | 每天8:00执行 |
延迟单次任务 | SimpleTrigger.withRepeatCount(0) | 5分钟后执行一次 |
工作日调度 | CronTrigger + 特殊日历 | 周一到周五9:00执行 |