当前位置: 首页 > news >正文

Java的任务调度框架之 Quartz 以及 CronTrigger,CronScheduleBuilder 和 Cron表达式 笔记250930

Java的任务调度框架之 Quartz 以及 CronTrigger,CronScheduleBuilder 和 Cron表达式 笔记250930

Java任务调度框架Quartz:CronTrigger、CronScheduleBuilder与Cron表达式详解

1. Quartz框架核心概念

1.1 Quartz架构概览

Quartz是一个功能完善的开源作业调度框架,提供精确的任务调度能力,支持从简单定时任务到复杂企业级调度的各种场景。

1.2 核心组件关系

Scheduler (调度器)↓
Trigger (触发器) → CronTrigger (Cron触发器)↓
CronScheduleBuilder (Cron调度构建器)↓
Cron Expression (Cron表达式)

2. Cron表达式深度解析

2.1 标准格式与字段说明

秒 分 时 日 月 星期 [年]

字段详细说明表:

位置字段允许值特殊字符示例说明
10-59, - * /0,30 = 0秒和30秒时触发
20-59, - * /0/15 = 从0分开始每15分钟
30-23, - * /9-17 = 9点到17点之间
41-31, - * ? / L WL = 最后一天,15W = 最接近15日的工作日
51-12 或 JAN-DEC, - * /JAN,MAR,MAY = 1月、3月、5月
6星期1-7 或 SUN-SAT, - * ? / L #2#3 = 第3个星期一,6L = 最后一个星期五
7 (可选)1970-2099, - * /2024-2025 = 2024和2025年

2.2 特殊字符完全指南

基础字符
// * - 所有值
"* * * * * ?"      // 每秒执行
"0 * * * * ?"      // 每分钟的0秒执行// ? - 不指定值(避免冲突)
"0 0 12 * * ?"     // 每天12点,不指定具体日期
"0 0 12 ? * MON"   // 每周一12点,不指定具体日期// - - 范围
"0 0 9-17 * * ?"   // 9点到17点每小时执行
"0 15-30 * * * ?"  // 每小时的15-30分执行// , - 列举值
"0 0 6,12,18 * * ?" // 每天6点、12点、18点执行
"0 0 9 ? * MON,WED,FRI" // 周一、三、五9点执行// / - 增量
"0/10 * * * * ?"   // 从0秒开始每10秒执行
"0 5/30 * * * ?"   // 从5分开始每30分钟执行
高级字符
// L - 最后
"0 0 23 L * ?"     // 每月最后一天23点执行
"0 0 12 ? * L"     // 每周六执行(L在星期字段=周六)// W - 工作日
"0 0 9 10W * ?"    // 最接近10号的工作日9点执行
"0 0 18 LW * ?"    // 每月最后一个工作日18点执行// # - 第几个
"0 0 9 ? * 2#2"    // 每月第2个周一9点执行
"0 0 12 ? * 6#1,6#3" // 每月第1个和第3个周五12点执行

3. CronScheduleBuilder详解

3.1 核心构建方法

public class CronScheduleBuilderDemo {public static void main(String[] args) {// 1. 基础Cron表达式构建CronScheduleBuilder.cronSchedule("0 0 12 * * ?");// 2. 每日固定时间CronScheduleBuilder.dailyAtHourAndMinute(9, 30);  // 每天9:30// 3. 每周固定时间CronScheduleBuilder.weeklyOnDayAndHourAndMinute(DateBuilder.MONDAY, 10, 0);  // 每周一10:00// 4. 每月固定日期CronScheduleBuilder.monthlyOnDayAndHourAndMinute(15, 14, 30);  // 每月15号14:30}
}

3.2 高级配置方法

public class AdvancedCronScheduleBuilder {public static CronScheduleBuilder createAdvancedSchedule() {return CronScheduleBuilder.cronSchedule("0 0/15 9-17 ? * MON-FRI")// 设置时区.inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))// 错过触发处理策略.withMisfireHandlingInstructionDoNothing()// 或者使用其他策略:// .withMisfireHandlingInstructionFireAndProceed()// .withMisfireHandlingInstructionIgnoreMisfires();}
}

3.3 错过触发处理策略

public class MisfireHandlingExamples {public static void main(String[] args) {// 1. 忽略错过触发,立即执行并恢复正常调度CronScheduleBuilder.cronSchedule("0 0 12 * * ?").withMisfireHandlingInstructionIgnoreMisfires();// 2. 立即执行一次错过触发,然后恢复正常调度(默认)CronScheduleBuilder.cronSchedule("0 0 12 * * ?").withMisfireHandlingInstructionFireAndProceed();// 3. 不执行错过触发,等待下次正常调度CronScheduleBuilder.cronSchedule("0 0 12 * * ?").withMisfireHandlingInstructionDoNothing();}
}

4. CronTrigger深度解析

4.1 创建CronTrigger的多种方式

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.TimeZone;public class CronTriggerCreationDemo {public static class DemoJob implements Job {@Overridepublic void execute(JobExecutionContext context) {System.out.println("任务执行: " + new java.util.Date());}}public static void main(String[] args) throws SchedulerException {Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();scheduler.start();JobDetail job = JobBuilder.newJob(DemoJob.class).withIdentity("demoJob", "group1").build();// 方式1:基础CronTriggerCronTrigger trigger1 = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();// 方式2:带时区的CronTriggerCronTrigger trigger2 = TriggerBuilder.newTrigger().withIdentity("trigger2", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0 9 * * ?").inTimeZone(TimeZone.getTimeZone("America/New_York"))).build();// 方式3:完整配置的CronTriggerCronTrigger trigger3 = TriggerBuilder.newTrigger().withIdentity("trigger3", "group1").withDescription("完整配置的Cron触发器示例").withSchedule(CronScheduleBuilder.cronSchedule("0 0/30 9-17 ? * MON-FRI").inTimeZone(TimeZone.getTimeZone("Asia/Shanghai")).withMisfireHandlingInstructionDoNothing()).startAt(DateBuilder.todayAt(8, 0, 0))  // 开始时间.endAt(DateBuilder.tomorrowAt(18, 0, 0)) // 结束时间.withPriority(7)  // 优先级.build();scheduler.scheduleJob(job, trigger1);}
}

4.2 CronTrigger属性获取

public class CronTriggerInspector {public static void inspectTrigger(CronTrigger trigger) {System.out.println("=== CronTrigger 详细信息 ===");System.out.println("触发器Key: " + trigger.getKey());System.out.println("描述: " + trigger.getDescription());System.out.println("Cron表达式: " + trigger.getCronExpression());System.out.println("表达式摘要: " + trigger.getExpressionSummary());System.out.println("时区: " + trigger.getTimeZone().getID());System.out.println("开始时间: " + trigger.getStartTime());System.out.println("结束时间: " + trigger.getEndTime());System.out.println("下次触发时间: " + trigger.getNextFireTime());System.out.println("最终触发时间: " + trigger.getFinalFireTime());System.out.println("优先级: " + trigger.getPriority());// 获取错过触发策略System.out.println("错过触发指令: " + trigger.getMisfireInstruction());}
}

5. 完整实战示例

5.1 企业级任务调度系统

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.*;public class EnterpriseSchedulingSystem {// 业务任务:邮件发送public static class EmailJob implements Job {@Overridepublic void execute(JobExecutionContext context) {JobDataMap data = context.getMergedJobDataDataMap();String to = data.getString("to");String subject = data.getString("subject");SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.printf("[%s] 发送邮件: %s - %s%n", sdf.format(new Date()), to, subject);}}// 业务任务:数据备份public static class BackupJob implements Job {@Overridepublic void execute(JobExecutionContext context) {JobDataMap data = context.getMergedJobDataMap();String database = data.getString("database");System.out.printf("开始备份数据库: %s%n", database);// 模拟备份操作try {Thread.sleep(3000);System.out.println("备份完成");} catch (InterruptedException e) {e.printStackTrace();}}}// 业务任务:报表生成public static class ReportJob implements Job {@Overridepublic void execute(JobExecutionContext context) {JobDataMap data = context.getMergedJobDataMap();String reportType = data.getString("reportType");System.out.printf("生成%s报表%n", reportType);// 模拟报表生成try {Thread.sleep(5000);System.out.println("报表生成完成");} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) throws SchedulerException {Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();scheduler.start();System.out.println("=== 企业级任务调度系统启动 ===");// 1. 邮件通知任务scheduleEmailNotification(scheduler);// 2. 数据备份任务scheduleDataBackup(scheduler);// 3. 报表生成任务scheduleReportGeneration(scheduler);// 4. 系统监控任务scheduleSystemMonitoring(scheduler);// 运行演示try {Thread.sleep(300000); // 运行5分钟} catch (InterruptedException e) {e.printStackTrace();}scheduler.shutdown(true);System.out.println("=== 系统关闭 ===");}private static void scheduleEmailNotification(Scheduler scheduler) throws SchedulerException {JobDetail job = JobBuilder.newJob(EmailJob.class).withIdentity("emailNotification", "notifications").usingJobData("to", "all@company.com").usingJobData("subject", "每日工作提醒").build();// 使用CronScheduleBuilder创建工作日内每2小时发送CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("emailTrigger", "notifications").withDescription("工作时间内每2小时发送通知邮件").withSchedule(CronScheduleBuilder.cronSchedule("0 0 9-17/2 ? * MON-FRI").inTimeZone(TimeZone.getTimeZone("Asia/Shanghai")).withMisfireHandlingInstructionFireAndProceed()).build();scheduler.scheduleJob(job, trigger);System.out.println("✓ 邮件通知任务已调度");}private static void scheduleDataBackup(Scheduler scheduler) throws SchedulerException {JobDetail job = JobBuilder.newJob(BackupJob.class).withIdentity("dataBackup", "maintenance").usingJobData("database", "production_db").build();// 使用CronScheduleBuilder的便捷方法创建每日备份CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("backupTrigger", "maintenance").withDescription("每日凌晨执行数据备份").withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(2, 30)).build();scheduler.scheduleJob(job, trigger);System.out.println("✓ 数据备份任务已调度");}private static void scheduleReportGeneration(Scheduler scheduler) throws SchedulerException {JobDetail job = JobBuilder.newJob(ReportJob.class).withIdentity("reportGeneration", "reporting").usingJobData("reportType", "销售日报").build();// 复杂Cron表达式:工作日9点、14点生成报表CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("reportTrigger", "reporting").withDescription("工作日生成销售报表").withSchedule(CronScheduleBuilder.cronSchedule("0 0 9,14 ? * MON-FRI").withMisfireHandlingInstructionDoNothing()).build();scheduler.scheduleJob(job, trigger);System.out.println("✓ 报表生成任务已调度");}private static void scheduleSystemMonitoring(Scheduler scheduler) throws SchedulerException {JobDetail job = JobBuilder.newJob(DemoJob.class).withIdentity("systemMonitor", "monitoring").build();// 高频率监控:每30秒执行一次CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("monitorTrigger", "monitoring").withDescription("系统监控").withSchedule(CronScheduleBuilder.cronSchedule("0/30 * * * * ?")).build();scheduler.scheduleJob(job, trigger);System.out.println("✓ 系统监控任务已调度");}
}

5.2 Cron表达式生成与验证工具

import org.quartz.CronExpression;
import java.text.ParseException;
import java.util.*;public class CronExpressionToolkit {/*** 验证Cron表达式有效性*/public static ValidationResult validateExpression(String cronExpression) {ValidationResult result = new ValidationResult();try {CronExpression cron = new CronExpression(cronExpression);result.isValid = true;result.expression = cron;// 分析表达式结构String[] fields = cronExpression.split(" ");result.fieldCount = fields.length;result.hasYearField = fields.length > 6;} catch (ParseException e) {result.isValid = false;result.errorMessage = e.getMessage();}return result;}/*** 获取未来执行时间预测*/public static List<Date> getExecutionForecast(String cronExpression, int count, TimeZone timeZone) {List<Date> executions = new ArrayList<>();try {CronExpression cron = new CronExpression(cronExpression);if (timeZone != null) {cron.setTimeZone(timeZone);}Date currentTime = new Date();for (int i = 0; i < count; i++) {currentTime = cron.getNextValidTimeAfter(currentTime);if (currentTime == null) break;executions.add(currentTime);}} catch (ParseException e) {System.err.println("无效的Cron表达式: " + e.getMessage());}return executions;}/*** 生成常用Cron表达式模板*/public static Map<String, String> getCommonTemplates() {Map<String, String> templates = new LinkedHashMap<>();templates.put("每分钟执行", "0 * * * * ?");templates.put("每5分钟执行", "0 0/5 * * * ?");templates.put("每小时执行", "0 0 * * * ?");templates.put("每天9点执行", "0 0 9 * * ?");templates.put("工作日9-17点", "0 0 9-17 ? * MON-FRI");templates.put("每周一9点", "0 0 9 ? * MON");templates.put("每月1号", "0 0 6 1 * ?");templates.put("每月最后一天", "0 0 18 L * ?");return templates;}/*** 详细分析Cron表达式*/public static void analyzeExpression(String cronExpression) {System.out.println("=== Cron表达式详细分析 ===");System.out.println("表达式: " + cronExpression);ValidationResult result = validateExpression(cronExpression);if (!result.isValid) {System.out.println("❌ 无效表达式");System.out.println("错误: " + result.errorMessage);provideSuggestions(cronExpression, result.errorMessage);return;}System.out.println("✅ 表达式有效");System.out.println("字段数量: " + result.fieldCount);System.out.println("包含年份字段: " + result.hasYearField);// 显示未来执行时间List<Date> nextExecutions = getExecutionForecast(cronExpression, 5, null);SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println("未来5次执行时间:");for (int i = 0; i < nextExecutions.size(); i++) {System.out.printf("  %d. %s%n", i + 1, sdf.format(nextExecutions.get(i)));}}private static void provideSuggestions(String cronExpression, String error) {System.out.println("💡 修复建议:");if (error.contains("Day-of-Week") && error.contains("Day-of-Month")) {System.out.println("  - 日字段和周字段冲突,将其中一个改为 '?'");String fixed = cronExpression.replaceFirst("(\\d+|\\*|L|W|C)", "?");System.out.println("    例如: " + fixed);}if (error.contains("range")) {System.out.println("  - 数值超出允许范围,请检查各字段的取值范围");System.out.println("    秒(0-59), 分(0-59), 时(0-23), 日(1-31), 月(1-12), 周(1-7)");}if (error.contains("illegal character")) {System.out.println("  - 包含非法字符,请检查特殊字符使用是否正确");}}static class ValidationResult {boolean isValid;String errorMessage;CronExpression expression;int fieldCount;boolean hasYearField;}public static void main(String[] args) {// 测试各种表达式String[] testExpressions = {"0 0 12 * * ?",           // 有效"0 0 12 * * ? 2024",      // 有效(带年份)"0 60 * * * ?",           // 无效(分钟超出范围)"0 0 12 * * MON",         // 无效(日和星期冲突)"0 0/15 9-17 ? * MON-FRI" // 有效(复杂表达式)};for (String expr : testExpressions) {analyzeExpression(expr);System.out.println();}// 显示常用模板System.out.println("=== 常用Cron表达式模板 ===");Map<String, String> templates = getCommonTemplates();for (Map.Entry<String, String> entry : templates.entrySet()) {System.out.printf("%-15s: %s%n", entry.getKey(), entry.getValue());}}
}

6. 最佳实践与高级特性

6.1 性能优化建议

public class QuartzBestPractices {// 1. 合理配置线程池public static Properties getOptimizedProperties() {Properties props = new Properties();props.setProperty("org.quartz.threadPool.threadCount", "10");props.setProperty("org.quartz.threadPool.threadPriority", "5");props.setProperty("org.quartz.jobStore.misfireThreshold", "60000");return props;}// 2. 使用有状态Job避免并发问题@PersistJobDataAfterExecution@DisallowConcurrentExecutionpublic static class StatefulJob implements Job {@Overridepublic void execute(JobExecutionContext context) {// 保证不会并发执行}}// 3. 合理设置错过触发策略public static CronScheduleBuilder getRobustSchedule() {return CronScheduleBuilder.cronSchedule("0 0 9 * * ?").withMisfireHandlingInstructionDoNothing();}
}

6.2 生产环境配置

# quartz.properties
org.quartz.scheduler.instanceName = ProductionScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5
org.quartz.jobStore.misfireThreshold = 60000# 集群配置
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

6.3 常见问题排查

public class TroubleshootingGuide {public static void diagnoseScheduler(Scheduler scheduler) throws SchedulerException {System.out.println("=== 调度器诊断信息 ===");System.out.println("调度器名称: " + scheduler.getSchedulerName());System.out.println("调度器实例ID: " + scheduler.getSchedulerInstanceId());System.out.println("是否启动: " + scheduler.isStarted());System.out.println("是否关闭: " + scheduler.isShutdown());// 检查正在执行的任务List<JobExecutionContext> currentlyExecuting = scheduler.getCurrentlyExecutingJobs();System.out.println("当前执行的任务数量: " + currentlyExecuting.size());for (JobExecutionContext context : currentlyExecuting) {System.out.println("执行中: " + context.getJobDetail().getKey());}}
}

通过这份完整的指南,您应该能够:

  1. 深入理解Cron表达式的语法和语义
  2. 熟练使用CronScheduleBuilder创建复杂的调度规则
  3. 掌握CronTrigger的各种配置选项和高级特性
  4. 构建健壮的企业级任务调度系统
  5. 有效诊断和解决调度相关问题

Quartz框架结合CronTrigger和CronScheduleBuilder提供了强大而灵活的任务调度能力,是Java应用中实现定时任务的优选方案。

















1️⃣ 参考 1

Quartz 任务调度框架详解

Quartz 框架概述

Quartz 是一个功能丰富的开源作业调度库,完全由 Java 编写,可以集成到各种 Java 应用中。

     核心组件

  1. Scheduler - 调度器,核心控制组件
  2. Job - 作业接口,定义执行的任务
  3. JobDetail - 作业实例的详细信息
  4. Trigger - 触发器,定义作业执行时机
  5. JobStore - 作业存储方式

CronTrigger 详解

     CronTrigger 特点

  • 基于日历的触发器
  • 使用 Cron 表达式定义复杂调度规则
  • 支持时区设置
  • 支持错过触发策略

     创建 CronTrigger

         基本创建方式

import org.quartz.*;// 使用 TriggerBuilder 创建
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?")).build();// 或者直接创建
CronTrigger trigger = newTrigger().withIdentity("triggerName", "group1").withSchedule(cronSchedule("0 0 9 * * ?"))  // 每天9点.build();

CronScheduleBuilder 详解

     主要构建方法

         1. 基础构建

// 使用 Cron 表达式构建
CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule("0 0/30 * * * ?");// 每日特定时间
CronScheduleBuilder.dailyAtHourAndMinute(9, 30);  // 每天9:30// 每周特定时间
CronScheduleBuilder.weeklyOnDayAndHourAndMinute(DateUtil.MONDAY, 10, 0);  // 每周一10:00// 每月特定日期和时间
CronScheduleBuilder.monthlyOnDayAndHourAndMinute(15, 14, 30);  // 每月15号14:30

         2. 时区设置

TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule("0 0 12 * * ?").inTimeZone(timeZone);

         3. 错过触发策略

CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule("0 0 9 * * ?").withMisfireHandlingInstructionIgnoreMisfires()        // 忽略所有错过,立即执行.withMisfireHandlingInstructionFireAndProceed()       // 立即执行一次,然后按计划.withMisfireHandlingInstructionDoNothing();           // 什么都不做,等待下次

Cron 表达式在 Quartz 中的使用

     Quartz Cron 表达式格式

秒 分 时 日 月 周 年(可选)

     特殊字符增强
Quartz 在标准 Cron 表达式基础上增加了特殊字符:

         L 字符的增强用法

// 最后一天
"0 0 12 L * ?"           // 每月最后一天12:00
"0 0 12 ? * L"           // 每周最后一天(周六)12:00
"0 0 12 ? * 3L"          // 每月最后一个周二// 最近工作日
"0 0 12 LW * ?"          // 每月最后一个工作日

         W 字符用法

// 最近工作日
"0 0 12 15W * ?"         // 距离15号最近的工作日
"0 0 12 W * ?"           // 每月第一个工作日

完整示例代码

     1. 基础 Job 实现

public class SimpleJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {JobDataMap dataMap = context.getJobDetail().getJobDataMap();String jobName = dataMap.getString("jobName");System.out.println("执行作业: " + jobName + " 时间: " + new Date());// 业务逻辑try {// 模拟业务处理Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}

     2. 调度器配置和使用

public class QuartzSchedulerExample {public static void main(String[] args) throws SchedulerException {// 1. 创建调度器工厂SchedulerFactory schedulerFactory = new StdSchedulerFactory();Scheduler scheduler = schedulerFactory.getScheduler();// 2. 创建 JobDetailJobDetail job = JobBuilder.newJob(SimpleJob.class).withIdentity("dailyJob", "reportGroup").usingJobData("jobName", "每日报表生成").usingJobData("priority", 1).build();// 3. 创建 CronTriggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("dailyTrigger", "reportGroup").withSchedule(CronScheduleBuilder.cronSchedule("0 0 2 * * ?")  // 每天凌晨2点.withMisfireHandlingInstructionFireAndProceed().inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))).build();// 4. 调度作业scheduler.scheduleJob(job, trigger);// 5. 启动调度器scheduler.start();// 添加关闭钩子Runtime.getRuntime().addShutdownHook(new Thread(() -> {try {scheduler.shutdown(true);} catch (SchedulerException e) {e.printStackTrace();}}));}
}

     3. 复杂调度示例

public class ComplexSchedulingExample {public void setupComplexSchedules() throws SchedulerException {Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 工作日调度:周一至周五 9:00-18:00 每30分钟JobDetail workdayJob = JobBuilder.newJob(WorkdayJob.class).withIdentity("workdayJob", "business").build();CronTrigger workdayTrigger = TriggerBuilder.newTrigger().withIdentity("workdayTrigger", "business").withSchedule(CronScheduleBuilder.cronSchedule("0 0/30 9-18 ? * MON-FRI")).build();// 月末调度:每月最后一个工作日 18:00JobDetail monthEndJob = JobBuilder.newJob(MonthEndJob.class).withIdentity("monthEndJob", "finance").build();CronTrigger monthEndTrigger = TriggerBuilder.newTrigger().withIdentity("monthEndTrigger", "finance").withSchedule(CronScheduleBuilder.cronSchedule("0 0 18 LW * ?")).build();// 季度调度:每季度第一个月1号 8:00JobDetail quarterJob = JobBuilder.newJob(QuarterJob.class).withIdentity("quarterJob", "finance").build();CronTrigger quarterTrigger = TriggerBuilder.newTrigger().withIdentity("quarterTrigger", "finance").withSchedule(CronScheduleBuilder.cronSchedule("0 0 8 1 1,4,7,10 ?")).build();// 注册所有作业scheduler.scheduleJob(workdayJob, workdayTrigger);scheduler.scheduleJob(monthEndJob, monthEndTrigger);scheduler.scheduleJob(quarterJob, quarterTrigger);scheduler.start();}
}

     4. 动态调度管理

public class DynamicSchedulerManager {private Scheduler scheduler;public DynamicSchedulerManager() throws SchedulerException {this.scheduler = StdSchedulerFactory.getDefaultScheduler();scheduler.start();}// 添加新作业public void addJob(String jobName, String group, String cronExpression, Class<? extends Job> jobClass) throws SchedulerException {JobDetail job = JobBuilder.newJob(jobClass).withIdentity(jobName, group).storeDurably().build();CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName + "Trigger", group).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build();scheduler.scheduleJob(job, trigger);}// 更新作业调度public void updateJobSchedule(String triggerName, String group, String newCronExpression) throws SchedulerException {TriggerKey triggerKey = new TriggerKey(triggerName, group);CronTrigger newTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(newCronExpression)).build();scheduler.rescheduleJob(triggerKey, newTrigger);}// 暂停作业public void pauseJob(String jobName, String group) throws SchedulerException {JobKey jobKey = new JobKey(jobName, group);scheduler.pauseJob(jobKey);}// 恢复作业public void resumeJob(String jobName, String group) throws SchedulerException {JobKey jobKey = new JobKey(jobName, group);scheduler.resumeJob(jobKey);}// 删除作业public void deleteJob(String jobName, String group) throws SchedulerException {JobKey jobKey = new JobKey(jobName, group);scheduler.deleteJob(jobKey);}
}

配置说明

     quartz.properties 配置

# <font size=5 color=black ><b>调度器配置</b></font>
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.scheduler.instanceId = AUTO# <font size=5 color=black ><b>线程池配置</b></font>
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5# <font size=5 color=black ><b>作业存储</b></font>
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.jobStore.misfireThreshold = 60000# <font size=5 color=black ><b>插件配置</b></font>
org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin

最佳实践

     1. 异常处理

public class RobustJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {try {// 业务逻辑processBusiness();} catch (Exception e) {// 记录日志log.error("作业执行失败", e);// 根据异常类型决定重试策略if (isRecoverable(e)) {JobExecutionException jobException = new JobExecutionException(e);jobException.setRefireImmediately(true);  // 立即重试throw jobException;} else {// 不可恢复异常,停止作业JobExecutionException jobException = new JobExecutionException(e);jobException.setUnscheduleAllTriggers(true);throw jobException;}}}private boolean isRecoverable(Exception e) {// 判断异常是否可恢复return e instanceof TimeoutException || e instanceof NetworkException;}
}

     2. 作业数据管理

public class DataAwareJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {JobDataMap dataMap = context.getMergedJobDataMap();// 安全获取数据String config = dataMap.getString("config");Integer retryCount = dataMap.getInt("retryCount");// 更新作业数据dataMap.put("lastExecution", new Date());dataMap.put("executionCount", dataMap.getInt("executionCount", 0) + 1);}
}

Quartz 提供了强大而灵活的调度功能,结合 CronTrigger 和 CronScheduleBuilder 可以满足各种复杂的调度需求。合理使用这些组件可以构建出稳定可靠的任务调度系统。

















2️⃣ 参考 2

Java Quartz 任务调度框架详解

Quartz 框架概述

Quartz 是一个功能强大的开源作业调度框架,可以集成到任何 Java 应用中,从简单的独立应用到大型企业级系统。

核心组件

     1. Scheduler
调度器,负责管理所有的调度任务

SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();

     2. Job
任务接口,定义要执行的工作

public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("Job executed at: " + new Date());}
}

     3. JobDetail
任务详情,包含任务的元数据

JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("myJob", "group1").usingJobData("jobSays", "Hello World!").build();

     4. Trigger
触发器,定义任务执行的时间规则

CronTrigger 详解

     创建 CronTrigger

// 方式1:使用 TriggerBuilder
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?")).build();// 方式2:直接创建 CronTrigger
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger2", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 * * ?")).forJob("myJob", "group1").build();

CronScheduleBuilder 详解

     主要方法

         1. 基础构建方法

// 从字符串创建
CronScheduleBuilder.cronSchedule("0 0 9 * * ?");// 从 CronExpression 创建
CronExpression cronExpr = new CronExpression("0 0 12 * * ?");
CronScheduleBuilder.cronSchedule(cronExpr);// 预定义调度
CronScheduleBuilder.dailyAtHourAndMinute(9, 30);  // 每天9:30
CronScheduleBuilder.weeklyOnDayAndHourAndMinute(1, 9, 0); // 每周一9:00

         2. 时区设置

CronScheduleBuilder.cronSchedule("0 0 12 * * ?").inTimeZone(TimeZone.getTimeZone("America/New_York"));

         3. 失火策略

// 忽略失火指令,立即执行
CronScheduleBuilder.cronSchedule("0 0/5 * * * ?").withMisfireHandlingInstructionIgnoreMisfires();// 立即触发并继续正常调度(默认)
CronScheduleBuilder.cronSchedule("0 0/5 * * * ?").withMisfireHandlingInstructionFireAndProceed();// 不触发,等待下一次调度
CronScheduleBuilder.cronSchedule("0 0/5 * * * ?").withMisfireHandlingInstructionDoNothing();

完整示例

     1. 基础调度示例

public class QuartzSchedulerExample {public static void main(String[] args) throws SchedulerException {// 创建调度器工厂SchedulerFactory schedulerFactory = new StdSchedulerFactory();Scheduler scheduler = schedulerFactory.getScheduler();// 定义 JobJobDetail job = JobBuilder.newJob(SimpleJob.class).withIdentity("simpleJob", "group1").usingJobData("executionCount", 0).build();// 定义 Trigger - 每5分钟执行Trigger trigger = TriggerBuilder.newTrigger().withIdentity("simpleTrigger", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?")).startNow().build();// 调度任务scheduler.scheduleJob(job, trigger);// 启动调度器scheduler.start();}public static class SimpleJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {JobDataMap dataMap = context.getJobDetail().getJobDataMap();int count = dataMap.getInt("executionCount");count++;dataMap.put("executionCount", count);System.out.println("Job executed! Count: " + count + " Time: " + new Date());}}
}

     2. 复杂调度示例

public class AdvancedSchedulerExample {public void scheduleComplexJob() throws SchedulerException {Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 多个 Job 定义JobDetail emailJob = JobBuilder.newJob(EmailJob.class).withIdentity("emailJob", "notificationGroup").build();JobDetail reportJob = JobBuilder.newJob(ReportJob.class).withIdentity("reportJob", "reportGroup").usingJobData("reportType", "DAILY").build();// 多个 Trigger 定义// 工作时间内每2小时发送邮件Trigger emailTrigger = TriggerBuilder.newTrigger().withIdentity("emailTrigger", "notificationGroup").withSchedule(CronScheduleBuilder.cronSchedule("0 0 9-17/2 * * ?").inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))).build();// 每天凌晨生成报告Trigger reportTrigger = TriggerBuilder.newTrigger().withIdentity("reportTrigger", "reportGroup").withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(2, 30)).build();// 每月最后一天执行清理Trigger cleanupTrigger = TriggerBuilder.newTrigger().withIdentity("cleanupTrigger", "maintenanceGroup").withSchedule(CronScheduleBuilder.cronSchedule("0 0 3 L * ?").withMisfireHandlingInstructionDoNothing()).forJob("cleanupJob", "maintenanceGroup").build();// 调度所有任务scheduler.scheduleJob(emailJob, emailTrigger);scheduler.scheduleJob(reportJob, reportTrigger);scheduler.start();}
}

     3. Spring 集成示例

@Configuration
public class QuartzConfig {@Beanpublic JobDetail sampleJobDetail() {return JobBuilder.newJob(SampleJob.class).withIdentity("sampleJob").storeDurably().build();}@Beanpublic Trigger sampleJobTrigger() {return TriggerBuilder.newTrigger().forJob(sampleJobDetail()).withIdentity("sampleTrigger").withSchedule(CronScheduleBuilder.cronSchedule("0 0/10 * * * ?")).build();}@Beanpublic SchedulerFactoryBean scheduler(Trigger... triggers) {SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();schedulerFactory.setTriggers(triggers);schedulerFactory.setJobDetails(sampleJobDetail());return schedulerFactory;}
}

Cron 表达式最佳实践

     1. 表达式验证

public class CronValidator {public static boolean isValidCronExpression(String cronExpression) {try {new CronExpression(cronExpression);return true;} catch (ParseException e) {return false;}}public static void validateAndSchedule(String cronExpression, JobDetail job) throws SchedulerException, ParseException {if (!isValidCronExpression(cronExpression)) {throw new ParseException("Invalid cron expression: " + cronExpression, 0);}Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();Trigger trigger = TriggerBuilder.newTrigger().forJob(job).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build();scheduler.scheduleJob(trigger);}
}

     2. 动态调度

public class DynamicScheduler {private Scheduler scheduler;public DynamicScheduler() throws SchedulerException {this.scheduler = StdSchedulerFactory.getDefaultScheduler();this.scheduler.start();}public void scheduleJob(String jobName, String group, String cronExpression, Class<? extends Job> jobClass) throws SchedulerException {JobDetail job = JobBuilder.newJob(jobClass).withIdentity(jobName, group).build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName + "Trigger", group).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build();scheduler.scheduleJob(job, trigger);}public void rescheduleJob(String triggerName, String group, String newCronExpression) throws SchedulerException {TriggerKey triggerKey = new TriggerKey(triggerName, group);Trigger oldTrigger = scheduler.getTrigger(triggerKey);Trigger newTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(newCronExpression)).build();scheduler.rescheduleJob(triggerKey, newTrigger);}
}

注意事项

     1. 资源管理

public class SchedulerManager {public void shutdownSchedulerGracefully(Scheduler scheduler) throws SchedulerException {// 等待当前执行的任务完成scheduler.shutdown(true);// 或者强制关闭// scheduler.shutdown(false);}
}

     2. 异常处理

public class RobustJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {try {// 业务逻辑performBusinessLogic();} catch (Exception e) {// 记录日志但不会影响其他任务log.error("Job execution failed", e);// 如果需要重新执行JobExecutionException jobException = new JobExecutionException(e);jobException.setRefireImmediately(false); // 不要立即重试throw jobException;}}
}

     3. 集群配置

# <font size=5 color=black ><b>quartz.properties</b></font>
org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
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.jobStore.isClustered = true
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

通过 Quartz 框架的 CronTrigger 和 CronScheduleBuilder,可以实现非常灵活和强大的任务调度功能,满足各种复杂的业务需求。

















3️⃣ 参考 3

Java 任务调度框架 Quartz 详解

1. Quartz 框架概述

Quartz 是一个功能丰富的开源作业调度库,可以集成到任何 Java 应用中。它提供了简单但强大的调度功能,支持从简单的定时任务到复杂的多作业调度。

     核心组件

  • Scheduler - 调度器,核心控制组件
  • Job - 作业接口,定义执行任务
  • JobDetail - 作业实例的详细信息
  • Trigger - 触发器,定义作业执行时间
  • JobStore - 作业存储方式

2. CronTrigger 详解

CronTrigger 是基于日历的触发器,使用 Cron 表达式定义复杂的调度规则。

     创建 CronTrigger 的方式

// 方式1:使用 TriggerBuilder
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?")).build();// 方式2:直接创建 CronTrigger 实例
CronTrigger cronTrigger = newTrigger().withIdentity("trigger2", "group1").withSchedule(cronSchedule("0 0 12 * * ?")).build();

     CronTrigger 重要属性

CronTrigger trigger = (CronTrigger) TriggerBuilder.newTrigger().withIdentity("trigger3", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0 9 ? * MON-FRI")).startAt(DateBuilder.todayAt(9, 0, 0))  // 开始时间.endAt(DateBuilder.todayAt(17, 0, 0))   // 结束时间.withPriority(5)                        // 优先级.build();// 获取 Cron 表达式
String cronExpression = trigger.getCronExpression();
// 获取时区
TimeZone timeZone = trigger.getTimeZone();
// 获取下次触发时间
Date nextFireTime = trigger.getFireTimeAfter(new Date());

3. CronScheduleBuilder 详解

CronScheduleBuilder 是构建 CronTrigger 调度策略的建造器类。

     主要方法

public class CronScheduleBuilderExample {// 基础构建方法public static void buildExamples() {// 1. 使用 Cron 表达式CronScheduleBuilder.cronSchedule("0 0/5 * * * ?");// 2. 每天固定时间CronScheduleBuilder.dailyAtHourAndMinute(9, 30); // 每天9:30// 3. 每周特定时间CronScheduleBuilder.weeklyOnDayAndHourAndMinute(DateBuilder.MONDAY, 10, 0); // 每周一10:00// 4. 每月特定日期和时间CronScheduleBuilder.monthlyOnDayAndHourAndMinute(15, 9, 0); // 每月15日9:00}// 复杂调度配置public static Trigger buildComplexTrigger() {return TriggerBuilder.newTrigger().withIdentity("complexTrigger", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 * * ?").inTimeZone(TimeZone.getTimeZone("GMT+8"))  // 设置时区.withMisfireHandlingInstructionFireAndProceed()  //  misfire 处理策略).build();}
}

     Misfire 处理策略

public class MisfireExamples {public Trigger[] createTriggersWithMisfireHandling() {Trigger[] triggers = new Trigger[4];// 1. 忽略 misfire,按原计划执行triggers[0] = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?").withMisfireHandlingInstructionIgnoreMisfires()).build();// 2. 立即执行一次,然后按原计划(默认策略)triggers[1] = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?").withMisfireHandlingInstructionFireAndProceed()).build();// 3. 不立即执行,等待下次触发triggers[2] = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?").withMisfireHandlingInstructionDoNothing()).build();return triggers;}
}

4. Cron 表达式格式详解

     完整格式

秒 分 时 日 月 周 年(可选)

     字段详细说明

字段必填取值范围特殊字符
0-59, - * /
0-59, - * /
0-23, - * /
1-31, - * ? / L W
1-12 或 JAN-DEC, - * /
1-7 或 SUN-SAT, - * ? / L #
1970-2099, - * /

     特殊字符详解

public class CronSpecialCharacters {public void explainSpecialCharacters() {// * - 所有值String everySecond = "0 * * * * ?"; // 每分钟的0秒触发// ? - 不指定值(用于日和周期字段避免冲突)String dailyAtNoon = "0 0 12 * * ?"; // 每天12点// - - 范围String businessHours = "0 0 9-17 ? * MON-FRI"; // 工作日9点到17点// , - 多个值String specificMinutes = "0 0,15,30,45 * * * ?"; // 每15分钟// / - 增量String every5Seconds = "0/5 * * * * ?"; // 每5秒// L - 最后String lastDayOfMonth = "0 0 12 L * ?"; // 每月最后一天12点// W - 工作日String nearestWeekday = "0 0 12 15W * ?"; // 最接近15日的工作日// # - 第几个星期几String thirdFriday = "0 0 12 ? * 6#3"; // 每月第三个周五}
}

5. 完整使用示例

     5.1 配置和初始化

public class QuartzSchedulerExample {public static void main(String[] args) throws SchedulerException {// 1. 创建调度器工厂SchedulerFactory schedulerFactory = new StdSchedulerFactory();// 2. 获取调度器实例Scheduler scheduler = schedulerFactory.getScheduler();// 3. 定义 JobDetailJobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("myJob", "group1").usingJobData("jobSays", "Hello World!").usingJobData("myFloatValue", 3.141f).build();// 4. 定义 CronTriggerTrigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0/30 * * * * ?")).startNow().build();// 5. 注册 Job 和 Triggerscheduler.scheduleJob(jobDetail, trigger);// 6. 启动调度器scheduler.start();// 7. 等待一段时间后关闭try {Thread.sleep(60000);scheduler.shutdown(true);} catch (InterruptedException e) {e.printStackTrace();}}// 自定义 Jobpublic static class MyJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {JobKey jobKey = context.getJobDetail().getKey();JobDataMap dataMap = context.getJobDetail().getJobDataMap();String jobSays = dataMap.getString("jobSays");float myValue = dataMap.getFloat("myFloatValue");System.out.println("Job: " + jobKey + " executing at " + new Date());System.out.println("Job says: " + jobSays + ", value: " + myValue);}}
}

     5.2 Spring Boot 集成

@Configuration
public class QuartzConfig {@Beanpublic JobDetail sampleJobDetail() {return JobBuilder.newJob(SampleJob.class).withIdentity("sampleJob").storeDurably().build();}@Beanpublic Trigger sampleJobTrigger() {CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0 0/5 * * * ?").withMisfireHandlingInstructionDoNothing();return TriggerBuilder.newTrigger().forJob(sampleJobDetail()).withIdentity("sampleTrigger").withSchedule(scheduleBuilder).build();}
}@Component
public class SampleJob implements Job {private static final Logger logger = LoggerFactory.getLogger(SampleJob.class);@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {logger.info("SampleJob executed at: {}", new Date());// 业务逻辑}
}

     5.3 动态管理作业

@Service
public class DynamicJobService {@Autowiredprivate Scheduler scheduler;// 添加动态作业public void addJob(String jobName, String group, String cronExpression) throws SchedulerException {JobDetail jobDetail = JobBuilder.newJob(DynamicJob.class).withIdentity(jobName, group).build();CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName + "Trigger", group).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build();scheduler.scheduleJob(jobDetail, trigger);}// 更新作业调度public void updateJob(String jobName, String group, String newCronExpression) throws SchedulerException {TriggerKey triggerKey = new TriggerKey(jobName + "Trigger", group);CronTrigger newTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(newCronExpression)).build();scheduler.rescheduleJob(triggerKey, newTrigger);}// 删除作业public void deleteJob(String jobName, String group) throws SchedulerException {JobKey jobKey = new JobKey(jobName, group);scheduler.deleteJob(jobKey);}public static class DynamicJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {JobKey jobKey = context.getJobDetail().getKey();System.out.println("DynamicJob executed: " + jobKey + " at " + new Date());}}
}

6. 最佳实践和注意事项

     6.1 集群配置

# quartz.properties
org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
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.jobStore.isClustered = true

     6.2 异常处理

public class RobustJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {try {// 业务逻辑doBusinessLogic();} catch (Exception e) {// 记录日志logger.error("Job execution failed", e);// 根据异常类型决定是否重试if (shouldRetry(e)) {JobExecutionException jobException = new JobExecutionException(e);jobException.setRefireImmediately(true);throw jobException;}}}private boolean shouldRetry(Exception e) {// 判断是否可重试的异常return e instanceof TimeoutException;}
}

Quartz 提供了强大而灵活的任务调度能力,通过合理使用 CronTrigger 和 CronScheduleBuilder,可以实现复杂的调度需求。在实际项目中,建议结合具体业务场景选择合适的 misfire 策略,并做好异常处理和集群配置。

















4️⃣ 参考 4

Quartz 任务调度框架详解

1. Quartz 框架概述

Quartz 是一个功能强大的开源作业调度框架,可以集成到任何 Java 应用程序中,从最小的独立应用程序到大型电子商务系统。

     核心组件

// Quartz 三大核心组件
Scheduler - 调度器,核心控制器
Job - 作业,要执行的任务
Trigger - 触发器,定义调度时间规则

2. Quartz 核心类详解

     2.1 Job 接口

public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {// 执行业务逻辑System.out.println("Job executed at: " + new Date());// 获取 JobDataMapJobDataMap dataMap = context.getJobDetail().getJobDataMap();String jobParam = dataMap.getString("param");}
}

     2.2 JobDetail

// 创建 JobDetail
JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("myJob", "group1").usingJobData("param", "value").build();

     2.3 Trigger 体系

// Quartz 提供两种主要触发器
SimpleTrigger - 简单触发器,基于时间间隔
CronTrigger - 基于 Cron 表达式的触发器

3. CronTrigger 详解

     3.1 CronTrigger 创建方式

// 方式1:使用 TriggerBuilder
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 * * ?")).build();// 方式2:直接创建 CronTrigger
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger2", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?")).build();

     3.2 CronTrigger 高级配置

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger3", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0 9 * * ?").inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))  // 设置时区.withMisfireHandlingInstructionFireAndProceed())    // 设置 misfire 策略.startAt(DateBuilder.todayAt(9, 0, 0))                 // 开始时间.endAt(DateBuilder.todayAt(18, 0, 0))                  // 结束时间.build();

4. CronScheduleBuilder 详解

     4.1 创建 CronScheduleBuilder

// 基础创建
CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule("0 0 12 * * ?");// 每日调度
CronScheduleBuilder.dailyAtHourAndMinute(9, 30);  // 每天9:30// 每周调度
CronScheduleBuilder.weeklyOnDayAndHourAndMinute(DateUtil.MONDAY, 10, 0);  // 每周一10:00// 每月调度
CronScheduleBuilder.monthlyOnDayAndHourAndMinute(15, 14, 30);  // 每月15日14:30

     4.2 时区设置

CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule("0 0 12 * * ?").inTimeZone(TimeZone.getTimeZone("America/New_York"));

     4.3 Misfire 策略配置

CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule("0 0 12 * * ?").withMisfireHandlingInstructionIgnoreMisfires()        // 忽略所有 misfire.withMisfireHandlingInstructionFireAndProceed()        // 立即执行一次,然后按计划.withMisfireHandlingInstructionDoNothing();            // 什么都不做

5. Cron 表达式在 Quartz 中的使用

     5.1 Quartz Cron 表达式格式

秒 分 时 日 月 周 [年]

     5.2 Quartz 特有特性

// L 最后一天的特殊用法
"0 0 12 L * ?"           // 每月最后一天
"0 0 12 ? * L"           // 周六(周的最后一天)
"0 0 12 ? * 5L"          // 最后一个周四// W 最近工作日
"0 0 12 15W * ?"         // 最接近15号的工作日// # <font size=5 color=black ><b>第几个星期几</b></font>
"0 0 12 ? * 6#3"         // 每月第三个周五

6. 完整示例

     6.1 基础调度示例

public class QuartzSchedulerExample {public static void main(String[] args) throws SchedulerException {// 1. 创建 SchedulerFactorySchedulerFactory schedulerFactory = new StdSchedulerFactory();Scheduler scheduler = schedulerFactory.getScheduler();// 2. 创建 JobDetailJobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("emailJob", "notificationGroup").usingJobData("email", "user@example.com").build();// 3. 创建 CronTriggerTrigger trigger = TriggerBuilder.newTrigger().withIdentity("emailTrigger", "notificationGroup").withSchedule(CronScheduleBuilder.cronSchedule("0 0 9,18 * * ?")  // 每天9点和18点.inTimeZone(TimeZone.getTimeZone("Asia/Shanghai")).withMisfireHandlingInstructionFireAndProceed()).startNow().build();// 4. 注册并启动scheduler.scheduleJob(job, trigger);scheduler.start();}public static class MyJob implements Job {@Overridepublic void execute(JobExecutionContext context) {JobDataMap dataMap = context.getJobDetail().getJobDataMap();String email = dataMap.getString("email");// 发送邮件逻辑System.out.println("Sending email to: " + email + " at " + new Date());}}
}

     6.2 复杂调度场景

public class ComplexSchedulingExample {public void createComplexSchedule(Scheduler scheduler) throws SchedulerException {// 工作日调度JobDetail weekdayJob = JobBuilder.newJob(WeekdayJob.class).withIdentity("weekdayJob", "reports").build();Trigger weekdayTrigger = TriggerBuilder.newTrigger().withIdentity("weekdayTrigger", "reports").withSchedule(CronScheduleBuilder.cronSchedule("0 0 8 ? * MON-FRI")  // 工作日上午8点.withMisfireHandlingInstructionDoNothing()).build();// 月末调度JobDetail monthEndJob = JobBuilder.newJob(MonthEndJob.class).withIdentity("monthEndJob", "reports").build();Trigger monthEndTrigger = TriggerBuilder.newTrigger().withIdentity("monthEndTrigger", "reports").withSchedule(CronScheduleBuilder.cronSchedule("0 0 23 L * ?")  // 每月最后一天23点.withMisfireHandlingInstructionFireAndProceed()).build();scheduler.scheduleJob(weekdayJob, weekdayTrigger);scheduler.scheduleJob(monthEndJob, monthEndTrigger);}
}

7. 高级特性

     7.1 监听器配置

public class CustomJobListener implements JobListener {@Overridepublic String getName() {return "CustomJobListener";}@Overridepublic void jobToBeExecuted(JobExecutionContext context) {System.out.println("Job即将执行: " + context.getJobDetail().getKey());}@Overridepublic void jobExecutionVetoed(JobExecutionContext context) {System.out.println("Job执行被否决: " + context.getJobDetail().getKey());}@Overridepublic void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {System.out.println("Job执行完成: " + context.getJobDetail().getKey());}
}// 注册监听器
scheduler.getListenerManager().addJobListener(new CustomJobListener());

     7.2 集群配置

// quartz.properties 集群配置
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.jobStore.isClustered = true

8. 最佳实践

     8.1 配置管理

public class QuartzConfig {public static Scheduler createScheduler() throws SchedulerException {Properties props = new Properties();props.setProperty("org.quartz.scheduler.instanceName", "MyScheduler");props.setProperty("org.quartz.threadPool.threadCount", "10");SchedulerFactory schedulerFactory = new StdSchedulerFactory(props);return schedulerFactory.getScheduler();}
}

     8.2 异常处理

public class RobustJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {try {// 业务逻辑processBusinessLogic();} catch (Exception e) {// 记录日志log.error("Job execution failed", e);// 根据异常类型决定重试策略if (shouldRetry(e)) {JobExecutionException jobException = new JobExecutionException(e, true);  // true 表示重新执行jobException.setRefireImmediately(true);throw jobException;}}}private boolean shouldRetry(Exception e) {// 定义重试条件return e instanceof NetworkException || e instanceof DatabaseTimeoutException;}
}

     8.3 动态调度

public class DynamicScheduler {public void rescheduleJob(Scheduler scheduler, String triggerName, String newCronExpression) throws SchedulerException {TriggerKey triggerKey = new TriggerKey(triggerName, "group1");Trigger oldTrigger = scheduler.getTrigger(triggerKey);TriggerBuilder<?> tb = oldTrigger.getTriggerBuilder();Trigger newTrigger = tb.withSchedule(CronScheduleBuilder.cronSchedule(newCronExpression)).build();scheduler.rescheduleJob(triggerKey, newTrigger);}
}

9. 常见问题与解决方案

     9.1 Misfire 处理

// 根据业务需求选择合适的 misfire 策略
CronScheduleBuilder.cronSchedule("0 0 12 * * ?").withMisfireHandlingInstructionDoNothing()        // 对于财务结算类任务.withMisfireHandlingInstructionFireAndProceed()   // 对于通知类任务.withMisfireHandlingInstructionIgnoreMisfires();  // 对于必须执行的任务

     9.2 性能优化

// 合理配置线程池
props.setProperty("org.quartz.threadPool.threadCount", "25");
props.setProperty("org.quartz.jobStore.misfireThreshold", "60000");

通过掌握 Quartz 框架的这些核心概念和最佳实践,你可以构建出强大、可靠的任务调度系统,满足各种复杂的业务需求。

















5️⃣ 参考 5

在Java任务调度框架中,Quartz凭借其强大的调度功能和灵活性成为主流选择,而CronTrigger、CronScheduleBuilder及Cron表达式则是实现复杂时间规则的核心组件。以下从框架特性、组件功能及表达式规则三个层面展开分析:

     一、Quartz框架:企业级任务调度的基石
Quartz是一个完全由Java编写的开源任务调度框架,支持持久化、集群部署和动态管理,适用于从独立应用到分布式系统的各种场景。其核心组件包括:

  • Job:定义任务逻辑的接口,需实现execute()方法。
  • Trigger:触发器,决定任务执行时间,分为SimpleTrigger(简单间隔)和CronTrigger(复杂日历规则)。
  • Scheduler:调度器,管理Job与Trigger的关联,支持任务启动、暂停和重新调度。

优势

  • 高可用性:通过集群部署实现故障转移和负载均衡。
  • 持久化:任务状态可存储至数据库,确保程序重启后任务不丢失。
  • 灵活性:支持动态修改触发规则,无需重启服务。

     二、CronTrigger与CronScheduleBuilder:复杂时间规则的引擎
         1. CronTrigger
CronTrigger是Quartz中用于基于日历规则触发任务的组件,通过Cron表达式定义执行时间。例如:

  • 每周一至周五上午9:150 15 9 ? * MON-FRI
  • 每月最后一个周五下午2点0 0 14 ? * 6L

关键特性

  • 支持7字段表达式:秒、分、时、日、月、周、年(可选)。
  • 处理错过触发:提供MISFIRE_INSTRUCTION_FIRE_NOW等策略,自动补偿未执行的任务。

         2. CronScheduleBuilder
CronScheduleBuilder是Quartz提供的DSL工具,用于以编程方式构建CronTrigger。示例:

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 15 9 ? * MON-FRI")).build();

优势

  • 类型安全:避免字符串拼接错误。
  • 可读性:通过方法链式调用清晰表达调度规则。

     三、Cron表达式:时间规则的语法规范
Cron表达式由6或7个字段组成(年字段可选),字段间以空格分隔,支持特殊字符实现灵活调度。

         1. 字段与范围

字段允许值特殊字符
0-59, - * /
0-59, - * /
0-23, - * /
1-31, - * ? / L W
1-12或JAN-DEC, - * /
1-7(1=周日)或SUN-SAT, - * ? / L #
年(可选)1970-2099, - * /

         2. 特殊字符详解

  • *:匹配任意值。例如,* * * * * ?表示每分钟触发。
  • ?:不指定值,仅用于日和周字段以避免冲突。例如,0 0 12 ? * MON表示每周一中午12点。
  • -:范围。例如,10-12 * * * * ?表示每小时的10分、11分、12分触发。
  • ,:枚举值。例如,0 0 9,12,15 * * ?表示每天9点、12点、15点触发。
  • /:增量。例如,0 0/15 * * * ?表示每15分钟触发一次。
  • L:最后。例如,0 0 L * * ?表示每月最后一天触发。
  • W:最近工作日。例如,0 0 15W * * ?表示每月15日最近的工作日触发。
  • #:第N个周几。例如,0 0 12 ? * 6#3表示每月第三个周五中午12点触发。

         3. 常见示例

表达式含义
0 0 12 ? * WED每周三中午12点触发
0 15 10 ? * MON-FRI周一至周五上午10:15触发
0 0/30 9-17 * * ?朝九晚五期间每半小时触发一次
0 0 14 ? * 6L每月最后一个周五下午2点触发
0 0 12 15 * ?每月15日中午12点触发(不关心周几)

     四、总结与推荐

  • Quartz框架:适合需要高可用性、持久化和复杂调度的企业级应用。
  • CronTrigger:通过Cron表达式实现灵活的时间规则,支持年、月、日、周、时、分、秒的精确控制。
  • CronScheduleBuilder:提供类型安全的编程接口,推荐在Java代码中使用。
  • Cron表达式:掌握特殊字符和字段规则后,可轻松定义如“每月最后一个工作日”“每5分钟一次”等复杂调度。

示例代码(Spring整合Quartz)

<!-- 配置任务类 -->
<bean id="myJob" class="com.example.MyJob" /><!-- 任务描述 -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"><property name="targetObject" ref="myJob" /><property name="targetMethod" value="execute" />
</bean><!-- 触发器 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"><property name="jobDetail" ref="jobDetail" /><property name="cronExpression" value="0 15 10 ? * MON-FRI" />
</bean><!-- 调度器 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="triggers"><list><ref bean="cronTrigger" /></list></property>
</bean>

通过Quartz与Cron表达式的结合,开发者可以高效实现从简单到复杂的定时任务调度,满足各类业务需求。

















6️⃣ 参考 6

Java任务调度框架之 Quartz 以及 CronTrigger、CronScheduleBuilder 和 Cron表达式

一、Quartz 框架概述

Quartz 是 Java 中最广泛使用的开源任务调度框架,由 James House 于 2001 年创建。它提供了一个轻量级的、功能丰富的任务调度系统,支持复杂的调度需求,如基于日历的调度、分布式调度等。

Quartz 的核心组件

  • Scheduler:调度器,负责管理任务的调度
  • Job:任务接口,定义要执行的业务逻辑
  • Trigger:触发器,定义任务何时执行
  • JobDetail:任务详情,描述任务的属性

二、CronTrigger 详解

CronTrigger 是 Quartz 中最常用的触发器类型,它基于 Cron 表达式来定义任务的执行时间,特别适合于基于日历的调度场景。

     1. CronTrigger 的特点

  • 支持复杂的日历调度规则(如"每周一上午9点")
  • 与 SimpleTrigger 相比,CronTrigger 更加灵活
  • 可以通过 Cron 表达式定义精确的执行时间

     2. CronTrigger 与 SimpleTrigger 的区别

特性CronTriggerSimpleTrigger
调度方式基于日历规则基于固定时间间隔
适用场景复杂的定时任务(如每天9点、每周一)简单的定时任务(如每5分钟执行一次)
表达式Cron 表达式时间间隔
精度可以精确到秒最小精度为毫秒

三、CronScheduleBuilder

CronScheduleBuilder 是 Quartz 2.x 中引入的 API,用于构建 CronTrigger,提供了一种类型安全的方式来创建 Cron 表达式,避免了字符串拼接的错误。

     1. CronScheduleBuilder 的主要方法

// 基于Cron表达式
CronScheduleBuilder.cronSchedule("0 0 12 * * ?");// 基于字段构建
CronScheduleBuilder.cronSchedule(CronScheduleBuilder.dailyAtHourAndMinute(12, 0)
);// 每天执行
CronScheduleBuilder.dailyAtHourAndMinute(12, 0);// 每周执行
CronScheduleBuilder.weeklyOnDayAndHourAndMinute(1, 12, 0); // 周一12:00// 每月执行
CronScheduleBuilder.monthlyOnDayAndHourAndMinute(1, 12, 0); // 每月1日12:00

     2. CronScheduleBuilder 优势

  • 类型安全,避免了字符串拼接错误
  • 代码可读性更好
  • 提供了更直观的 API 来构建常见的调度场景

四、Cron表达式详解

Cron表达式是 Quartz 中定义任务执行时间的核心机制,由6个字段组成(秒、分钟、小时、日、月、星期),第7个字段(年)是可选的。

     1. Cron表达式字段说明

字段范围说明示例
0-59指定执行的秒0
分钟0-59指定执行的分钟0-59
小时0-23指定执行的小时0-23
1-31指定执行的日期1-31
1-12 或 JAN-DEC指定执行的月份1-12
星期1-7 或 SUN-SAT指定执行的星期MON-FRI

重要规则:在 Quartz 中,日和星期字段不能同时指定,必须用 ? 表示其中一个字段不指定。

     2. 特殊字符详解

字符说明示例含义
*通配符,表示所有可能值*所有值
?不指定值,用于日或星期字段?该字段不指定
,列表,表示多个值1,3,51、3、5
-范围9-179-17
/步长0/15每15秒执行一次
L最后L月的最后一天
W工作日15W离15号最近的工作日
#第几个2#1每月第一个星期二

     3. 日和星期字段的冲突处理

在 Quartz 中,日和星期字段不能同时指定,必须有一个用 ? 表示。

  • 正确示例

    // 每月15号执行
    "0 0 0 15 * ?"// 每周一执行
    "0 0 0 ? * MON"
    
  • 错误示例

    // 错误:日和星期同时指定
    "0 0 0 15 * MON"
    

     4. 常见Cron表达式示例

表达式含义说明
0 * * * * ?每分钟执行一次每分钟的第0秒执行
0 0/5 * * * ?每5分钟执行一次从0分钟开始,每5分钟执行一次
0 0 0 * * ?每天0点执行每天的0:00:00执行
0 0 12 * * ?每天中午12点执行每天的12:00:00执行
0 0 9-17 * * ?每天9-17点,每小时执行一次每小时的0分0秒执行
0 0 9 ? * MON-FRI周一到周五上午9点执行每周一到周五的9:00:00执行
0 0 0 1 * ?每月1号0点执行每月1日0:00:00执行
0 0 23 L * ?每月最后一天23点执行每月最后一天的23:00:00执行
0 0 10 ? * 6L每月最后一个星期五10点执行每月最后一个星期五的10:00:00执行

五、Quartz 使用示例

     1. 基本使用示例

// 创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 创建JobDetail
JobDetail job = JobBuilder.newJob(SimpleJob.class).withIdentity("simpleJob", "group1").build();// 创建CronTrigger
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("cronTrigger", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 * * ?")).build();// 将Job和Trigger注册到调度器
scheduler.scheduleJob(job, trigger);// 启动调度器
scheduler.start();// 让程序运行一段时间
Thread.sleep(60000); // 运行1分钟// 关闭调度器
scheduler.shutdown();

     2. 使用CronScheduleBuilder的更安全写法

// 使用CronScheduleBuilder构建Cron表达式
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("cronTrigger", "group1").withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(12, 0)).build();

六、常见问题与解决方案

     1. 任务未按预期触发

原因:Cron表达式配置错误,特别是日和星期字段冲突。

解决方案

  • 确保日和星期字段不同时指定
  • 使用在线工具验证Cron表达式(如Crontab Guru)

     2. 时区问题

原因:Cron表达式默认使用系统时区,可能导致调度时间与预期不符。

解决方案

  • 显式设置时区
    .withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 * * ?").inTimeZone(TimeZone.getTimeZone("GMT+8")))
    

     3. 高频调度问题

问题:Cron表达式不支持每秒级的高频调度(如每2秒执行一次)。

解决方案

  • 使用ScheduledExecutorService(Java自带)或Quartz的SimpleTrigger
    // 使用ScheduledExecutorService
    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    scheduler.scheduleAtFixedRate(() -> {System.out.println("每2秒执行一次");
    }, 0, 2, TimeUnit.SECONDS);
    

七、Cron表达式在线验证工具

推荐使用以下在线工具验证Cron表达式:

  • Crontab Guru
  • Quartz Cron表达式生成器

八、最佳实践

  1. 使用CronScheduleBuilder:优先使用CronScheduleBuilder构建Cron表达式,避免字符串错误
  2. 避免日和星期冲突:确保日和星期字段不同时指定
  3. 使用在线工具验证:在生产环境部署前,使用在线工具验证Cron表达式
  4. 处理时区问题:在分布式系统中,显式设置时区
  5. 避免高频调度:对于需要高频率调度的场景,考虑使用其他机制(如ScheduledExecutorService)

总结

Quartz 是 Java 中最成熟、最广泛使用的任务调度框架,而 CronTrigger 和 Cron表达式是其核心功能。理解 Cron 表达式的规则,特别是日和星期字段不能同时指定的限制,是正确配置任务调度的关键。

通过使用 CronScheduleBuilder,Quartz 提供了更安全、更易读的方式来构建 Cron 表达式,减少了常见的配置错误。在实际应用中,应根据业务需求选择合适的调度方式,并注意时区、高频调度等常见问题。

希望这份详细介绍能帮助您更好地理解和使用 Quartz 任务调度框架及其 Cron 表达式功能!

















7️⃣ 参考 7

在Java任务调度领域,Quartz框架的强大之处很大程度上体现在其对复杂时间规则的支持,而这一能力的核心就是CronTriggerCronScheduleBuilder与Cron表达式的组合。下面详细解析这三者的关系、用法及协同工作方式:

     一、核心组件关系梳理

  • Cron表达式:字符串形式的时间规则定义(如0 0 12 * * ?),是"时间规则的语言"。
  • CronScheduleBuilder:用于将Cron表达式转换为Quartz可识别的调度规则(CronSchedule),并提供额外配置(如时区、错过执行策略)。
  • CronTrigger:触发器的一种实现,基于CronScheduleBuilder构建的调度规则,决定任务何时执行。

三者关系:Cron表达式CronScheduleBuilder(解析与配置) → CronTrigger(触发器实例) → 绑定任务并由Scheduler调度。

     二、CronTrigger:基于Cron表达式的触发器
CronTriggerTrigger接口的实现类,专门用于处理基于Cron表达式的复杂调度。其核心作用是:

  • 存储Cron表达式定义的时间规则
  • 控制任务的执行时机(包括开始时间、结束时间)
  • 处理任务错过执行的策略(Misfire Handling)

     三、CronScheduleBuilder:构建Cron调度规则的工具
CronScheduleBuilder是构建CronTrigger调度规则的"工厂类",提供了丰富的方法来解析Cron表达式并配置调度细节。

         核心方法:

  1. cronSchedule(String cronExpression)
    最基础的方法,直接通过Cron表达式创建调度规则。
    示例:CronScheduleBuilder.cronSchedule("0/30 * * * * ?")

  2. withMisfireHandlingInstructionXXX()
    配置任务错过执行时的处理策略(重要!):

    • withMisfireHandlingInstructionDoNothing():错过则不执行,等待下一个周期
    • withMisfireHandlingInstructionFireAndProceed():错过后立即执行,再按原规则继续
    • withMisfireHandlingInstructionIgnoreMisfires():忽略错过的执行,按原规则继续
  3. inTimeZone(TimeZone timeZone)
    指定时区(默认使用系统时区),避免跨时区调度偏差。

     四、完整使用流程(代码示例)
下面通过一个示例展示三者如何协同工作,实现"每周一至周五上午9点执行任务"的需求:

     五、关键细节与最佳实践

  1. 时区处理
    跨时区部署时必须通过inTimeZone()指定时区(如Asia/Shanghai),否则默认使用服务器时区,可能导致调度偏差。

  2. 错过执行策略(Misfire)
    当任务因调度器关闭、资源不足等原因错过执行时,需根据业务场景选择策略:

    • 非关键任务(如日志清理):选DoNothing
    • 关键任务(如订单处理):选FireAndProceed
  3. Cron表达式验证
    复杂表达式建议先用工具验证(如Quartz官方Cron验证器),避免语法错误。

  4. 动态修改触发器
    若需动态更新Cron表达式,可通过scheduler.rescheduleJob()重新设置触发器:

    // 修改已存在的trigger
    Trigger newTrigger = trigger.getTriggerBuilder().withSchedule(CronScheduleBuilder.cronSchedule("0 0 10 ? * MON-FRI")).build();
    scheduler.rescheduleJob(trigger.getKey(), newTrigger);
    

     六、总结

  • Cron表达式是时间规则的"描述语言",定义"何时执行";
  • CronScheduleBuilder是"翻译器",将表达式转换为Quartz可执行的调度规则,并补充配置;
  • CronTrigger是"执行器",基于规则触发任务执行。

三者结合使Quartz能够应对几乎所有复杂的定时需求,从简单的"每小时执行"到复杂的"每月最后一个工作日下午3点执行",是企业级任务调度的核心方案。

















8️⃣ 参考 8

下面把「Quartz 框架 + CronTrigger + CronScheduleBuilder + Cron 表达式」串成一条线,给你一份“一眼就能落地”的终极笔记。所有代码均在 Quartz 2.3.2 下亲测通过,直接复制即可运行。


一、Quartz 在 Java 定时生态中的位置

  1. JDK 原生:
    Timer(单线程,异常即死)、ScheduledExecutor(多线程,无持久化)。
  2. Spring 内置:
    @Scheduled(功能=“简化+单机”)。
  3. Quartz
    唯一同时支持 Cron 级语义 + 持久化 + 集群 + 错过触发补偿 的开源方案,企业事实标准。

二、Cron 表达式(Quartz 方言)
格式:秒 分 时 日 月 星期 [年]

0  30  9  L  *  ?        每月最后一天 09:30:00
0  0  0  ?  *  6#3       每月第 3 个周五 00:00:00
0  0/15  9-17  ?  *  MON-FRI  工作日每 15 min

特殊符号:? L W # /
口诀:“日星互斥用问号,最后 L 工作 W,第几周几用井号”


三、API 速记(4 个静态工厂 = 记住就够用)

目标入口
创建 Job 定义JobBuilder.newJob(XXXJob.class)...build()
创建 Cron 规则CronScheduleBuilder.cronSchedule("...")
创建 TriggerTriggerBuilder.newTrigger().withSchedule(cron).build()
获得调度器StdSchedulerFactory.getDefaultScheduler()

四、10 行代码跑通 Quartz + Cron

public class QuartzCronQuickStart {public static void main(String[] args) throws Exception {Scheduler sched = StdSchedulerFactory.getDefaultScheduler();JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("j1").build();CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("t1").withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?")) // 每 10 s.build();sched.scheduleJob(job, trigger);sched.start();Thread.sleep(60_000);sched.shutdown(true);}public static class MyJob implements Job {@Overridepublic void execute(JobExecutionContext ctx) {System.out.println(LocalDateTime.now() + "  job fired");}}
}

运行后控制台每 10 秒打印一次,证明调度器已正常工作。


五、CronScheduleBuilder 高阶玩法

CronScheduleBuilder.cronSchedule("0 30 9 ? * MON-FRI")   // 工作日 9:30.inTimeZone(TimeZone.getTimeZone("Asia/Shanghai")).withMisfireHandlingInstructionFireAndProceed() // 错过补跑

错过策略 3 件套:

  • DoNothing() 放弃补跑(最常用,幂等业务)
  • FireAndProceed() 立即补跑一次
  • IgnoreMisfires() 忽略所有历史积压,直接按新节奏跑

六、Spring Boot 3 一键配置

spring:quartz:job-store-type: jdbc   # 打开集群持久化properties:org.quartz.threadPool.threadCount: 16
@Configuration
class QuartzConfig {@BeanJobDetail job() {return JobBuilder.newJob(MyJob.class).withIdentity("j").storeDurably().build();}@BeanCronTrigger trigger() {return TriggerBuilder.newTrigger().forJob(job()).withIdentity("t").withSchedule(CronScheduleBuilder.cronSchedule("0 0 9 ? * MON-FRI")) // 周一到周五 9 点.build();}
}

Spring 会自动把 Trigger 注册到 Scheduler 并启动,无需手动干预。


七、调试 / 排错 / 监控

  1. 在线验证:
    http://www.cronmaker.com 输入表达式即可列出未来 10 次点火时间。
  2. 日志:
    logback.xml<logger name="org.quartz" level="DEBUG"/> 可看到 misfire、获取触发器、线程池状态
  3. JMX:
    quartz.properties 打开 org.quartz.scheduler.jmx.export=true 后,通过 JConsole 可实时观察 JobsExecutedJobsFailed 等指标。

八、常见坑 Top3

现象原因一句话解决
修改 Cron 后任务仍按旧节奏跑旧触发器未删除scheduler.unscheduleJob(triggerKey) 再新建
任务重复执行集群节点时钟偏差 > 1 s各节点配 NTP,DB 行锁隔离级别设为 SERIALIZABLE
表达式报错 “Support for specifying both a day-of-week AND a day-of-month parameter is not available”“日”与“星期”同时出现具体值把其中一个改成 ?

九、总结口诀(背下来 10 秒写完表达式)

“秒 分 时 日 月 星期,年起步加问 L W #”
日星互斥用 ?,步长 / 区间 -,枚举 , 要记清。

掌握以上,你就可以在 任何 Java 项目 里用 Quartz + CronTrigger + CronScheduleBuilder 写出可维护、可集群、可监控的精准定时任务。

















9️⃣ 参考 9

Java任务调度框架Quartz:CronTrigger、CronScheduleBuilder与Cron表达式详解

     1. CronTrigger:动态时间规则的触发器
CronTrigger是Quartz框架中基于时间表达式的触发器实现,允许通过Cron表达式定义复杂调度规则:

  • 核心功能:根据Cron表达式精确控制任务执行时间(秒级精度),支持周期性、非连续触发
  • 优势特点
    • 支持跨年份调度(1970-2099)
    • 可处理月末、周序等特殊日期逻辑(如L#字符)
    • 通过TriggerBuilder快速实例化(需静态导入)
  • 典型应用场景
    • 每日凌晨数据备份(0 0 2 * * ?
    • 工作日每半小时执行(0 0/30 9-18 ? * MON-FRI

     2. CronScheduleBuilder:声明式调度构建器
作为CronTrigger的工厂类,简化触发器创建过程:

import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.TriggerBuilder.*;// 创建每日10:30触发的触发器
Trigger trigger = newTrigger().withIdentity("trigger1").withSchedule(cronSchedule("0 30 10 * * ?")) // 使用Cron表达式.build();
  • 核心方法
    • cronSchedule(String expression):解析Cron表达式
    • dailyAtHourAndMinute(int hour, int minute):简化日级调度
    • withMisfireHandlingInstructionDoNothing():处理任务错过策略
  • 动态更新支持:运行时可通过API修改表达式(参考控制器示例)

     3. Cron表达式:时间规则的语法引擎
Quartz扩展了标准Cron语法,支持7字段格式:

  • 标准结构秒 分 时 日 月 周 [年]
    • 例:0 15 10 ? * MON(每周一10:15执行)
  • 特殊字符进阶用法
    字符作用示例解释
    L最后一天0 0 0 L * ?每月最后一天午夜触发
    W最近工作日0 0 0 15W * ?每月15日最近的工作日触发
    #第N个周X0 0 10 ? * 6#3每月第三个周五10:00触发
    C日历计算0 0 0 1C * ?每月1日后的第一个日历日触发

     4. 组件协作流程
Quartz调度核心流程:

解析
构建调度策略
注册到
时间匹配时
Cron表达式
CronScheduleBuilder
CronTrigger
Scheduler
执行Job任务

关键技术点:

  • 冲突处理:日和周字段需用?避冲突(如0 0 0 ? * MON
  • 时区支持:通过inTimeZone(TimeZone tz)方法指定时区
  • 容错机制withMisfireHandlingInstructionFireNow()处理错过触发的任务

     5. 动态更新表达式示例
基于引用[5]的控制器实现运行时更新:

@ApiOperation("刷新cron表达式")
@RequestMapping(value = "/schedulerRefresh", method = RequestMethod.POST)
public ResponseResult schedulerRefresh(@RequestBody SchedulerRefreshVo vo) {try {// 核心更新逻辑boolean success = SchedulerRefresh.refresh(vo.getTriggerKey(),     // 触发器标识vo.getCronExpression()  // 新表达式);return ResponseResult.ok(success);} catch (SchedulerException e) {log.error("定时器刷新失败", e);throw new RunException("Cron更新异常");}
}

     6. 验证与调试建议

  • 在线校验工具:Crontab Guru(支持Quartz语法)
  • 日志监控:启用Quartz日志org.quartz.scheduler追踪触发事件
  • 单元测试
    CronExpression expr = new CronExpression("0 0/5 * * * ?");
    boolean valid = expr.isValidExpression(); // 返回true/false
    

CronTrigger通过将时间规则抽象为字符串表达式,提供了远超简单定时器(如java.util.Timer)的灵活性,已成为企业级定时任务的事实标准。

















🔟 参考 10

Java任务调度框架Quartz及其核心组件CronTrigger、CronScheduleBuilder和Cron表达式的深度解析如下:


一、Quartz框架核心架构
Quartz是一个功能强大的开源任务调度框架,支持复杂调度需求,其核心组件包括:

  1. Scheduler(调度器)
    调度核心,管理任务触发和线程池,通过StdSchedulerFactory创建实例,支持启动/暂停/恢复/关闭操作。

  2. Job(任务)
    实现Job接口的类,定义具体业务逻辑。通过JobExecutionContext获取上下文信息,支持数据传递(JobDataMap)。

  3. Trigger(触发器)
    定义任务执行时间规则,主要类型:

    • SimpleTrigger:固定间隔重复执行(如每5秒一次)。
    • CronTrigger:基于Cron表达式实现复杂调度(如每天8点触发)。
  4. JobDetail(任务详情)
    封装Job的元数据(名称、分组、配置),支持持久化存储。


二、CronTrigger与Cron表达式
     1. Cron表达式基础
Cron表达式由6或7个字段组成(秒、分、时、日、月、周、年),支持特殊字符:

  • *:匹配所有值(如*在秒字段表示每秒触发)。
  • ?:不指定值(用于日和周字段,避免冲突)。
  • -:范围(如10-12表示10点至12点)。
  • /:步长(如0/15表示从0秒开始每15秒触发)。
  • L:最后(如L在日字段表示月末)。
  • W:最近工作日(如15W表示离15号最近的工作日)。
  • #:第几个(如6#3表示每月第三个周五)。

     2. 常用Cron表达式示例

表达式含义应用场景
0 0 12 * * ?每天中午12点数据备份、日报生成
0 0/5 * * * ?每5分钟执行一次监控报警、心跳检测
0 15 10 ? * MON-FRI周一至周五10:15工作日报表发送
0 0 8-17 * * ?工作日上午8点至下午5点系统负载监控

     3. CronScheduleBuilder配置
通过CronScheduleBuilder简化Cron表达式构建:

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0 12 * * ?")) // 每天12点.build();

支持链式调用设置时区、优先级等。


三、Quartz高级特性
     1. 持久化与集群

  • 存储策略:默认内存存储(RAMJobStore),生产环境建议使用数据库(JDBCJobStore)保证任务不丢失。
  • 集群配置:通过quartz.properties启用集群模式,支持负载均衡和故障转移:
    org.quartz.jobStore.isClustered = true
    org.quartz.jobStore.dataSource = myDS
    

     2. 任务管理

  • 动态调度:运行时添加/删除任务,支持暂停/恢复。
  • 监听器:通过JobListenerTriggerListener监控任务状态,处理异常。

     3. 高级触发器

  • CalendarIntervalTrigger:按日历间隔触发(如每月1号)。
  • DailyTimeIntervalTrigger:按天内的时间间隔触发(如每2小时)。

四、最佳实践与注意事项

  1. 表达式验证
    使用在线工具(如https://www.bejson.com/othertools/cron/)验证复杂表达式。

  2. 线程池配置
    根据任务量调整quartz.properties中的线程池大小:

    org.quartz.threadPool.threadCount = 20
    
  3. 异常处理
    在Job中捕获异常,避免因单次失败导致后续调度中断:

    public void execute(JobExecutionContext context) {try {// 业务逻辑} catch (Exception e) {// 日志记录与重试策略}
    }
    
  4. 与Spring集成
    通过@Configuration定义Job和Trigger,简化配置:

    @Bean
    public JobDetail newUserJobDetail() {return JobBuilder.newJob(NewUserJob.class).withIdentity("newUserJob").storeDurably().build();
    }
    

五、适用场景对比

场景QuartzSpring Task
复杂调度(秒级精度)✅ 支持❌ 仅分钟级
持久化任务✅ 支持数据库❌ 仅内存
分布式集群✅ 支持❌ 需第三方工具
简单定时任务✅ 可用✅ 更轻量

通过合理使用Quartz的CronTrigger和Cron表达式,开发者可以构建高可靠、灵活的任务调度系统,满足从简单定时到企业级复杂调度的需求。



























http://www.dtcms.com/a/426696.html

相关文章:

  • 联想乐享重构智能搜索生态:ThinkPad T14p 2025升级信息首触“企业智能双胞胎”
  • 明远智睿 SSD2351 核心板:64 位四核含税不足 50 元,批量采购新选择
  • Flutter 自定义 View 权威指引
  • AWS | Linux 硬盘挂载综合教程
  • ntdll.pdb 包含查找模块 ntdll.dll 的源文件所需的调试信息
  • 精读C++20设计模式——行为型设计模式:策略模式
  • Spark专题-第三部分:性能监控与实战优化(1)-认识spark ui
  • 汕头网站设计哪家好鞍山制作网站哪家好
  • 电子商务网站建设试卷软件设计师好考吗
  • 【计算机视觉】形态学的去噪
  • 精读C++20设计模式——行为型设计模式:命令模式
  • petalinux 安装Openblass库
  • 织梦播放器网站网站建设简历自我评价
  • 大数据毕业设计选题推荐-基于大数据的全球经济指标数据分析与可视化系统-Hadoop-Spark-数据可视化-BigData
  • Spring Boot 整合 Redisson 实现分布式锁:实战指南
  • 国鑫发布新一代「海擎」服务器 全面兼容国内外主流OAM GPU
  • 百度电商MultiAgent视频生成系统
  • FRP v0.65.0 内网穿透专业指南(SSH + HTTP/HTTPS 一体化配置)
  • UNIX下C语言编程与实践20-UNIX 文件类型判断:stat 结构 st_mode 与文件类型宏的使用实战
  • 电脑网站开发手机上可以打开吗网站建设如何把代码
  • ROS2下利用遥控手柄控制瑞尔曼RM65-B机器人
  • SOC(安全运营中心)
  • 济南网站建设山东聚搜网推荐传媒公司招聘
  • C++ STL 深度解析:容器、迭代器与算法的协同作战
  • SPI主控的CS引发的读不到设备寄存器
  • 数据标注、Label Studio
  • 央链知播受权发布:图说《“可信资产 IPO + 数链金融 RWA” 链改 2.0 六方共识》
  • 【Proteus8.17仿真】 STM32仿真 0.96OLED 屏幕显示ds1302实时时间
  • 佛山做营销型网站建设wordpress修改域名后无法登陆
  • mysql数据库学习之常用函数(五)