Java 中的 Spring CronExpression 类

2025年2月25日 | 阅读 7 分钟

Cron 表达式是一个字符序列,用于定义在基于 Unix 的系统或 Java 等编程语言中执行任务的特定计划。它可以定期自动化任务,例如每天、每周或每月。 每个 cron 表达式包含六到七个字段,这些字段指示不同的时间单位,这些字段用空格分隔。

Cron 表达式字段和格式

这是 cron 表达式字段的细分

字段允许的值特殊字符
0-59, - * /
0-590-59, - * /
小时0-23, - * /
月份中的天1-31, - * ? / L W
月份1-12 或 JAN-DEC, - * /
星期中的天0-6 (SUN-SAT), - * ? / L #
年份 (可选)1970-2099, - * /

如何编写 Cron 表达式?

要生成 Cron 表达式,请遵循其六个部分的结构和指南:秒、分、时、月中日、月和星期几。 每个类别都表示特定的时间范围,包括诸如 *、-、,、/、?、L、W、# 和 C 等特殊符号,用于定制时间表。

这是一个编写 Spring Scheduling Cron 表达式的分步指南:

1. 基本格式

Cron 表达式由 6 或 7 个字段组成,这些字段定义了任务应何时执行

2. 符号和用法

  • 星号 (*): 表示字段的“每个”可能值。
    • 示例:该任务计划在每个小时的开始运行时,表达式为“0 0 * * * *”。
  • 逗号 (,): 指定值的列表。
    • 示例:“0 0 4,14 * * *”每天在凌晨 4:00下午 2:00 运行该任务。
  • 短划线 (-): 指定值的范围。
    • 示例:“0 0 2-4 * * *”每天在凌晨 2:00、3:00 和 4:00 运行该任务。
  • 正斜杠 (/): 指定增量。
    • 示例:“0 0/30 2-4 * * *”从凌晨 2:00 到凌晨 4:3030 分钟运行该任务。
  • 问号 (?): 表示“没有特定值”。 它用于月中日星期几字段。
    • 示例:“0 0 10 ? * MON”在每个星期一的上午 10:00 运行该任务。
  • L(Last): 在月中日或星期几的字段中使用,以指示该月或该周的最后一天。
    • 示例:“0 0 0 L * *”在该月的最后一天的午夜运行该任务。
  • W(Weekday): 用于月中日字段中,以指示最近的工作日。
    • 示例:“0 0 0 1W * *”在该月 1 号最近的工作日运行该任务。
  • 井号 (#): 用于星期几字段中,以指定“该月的第 n 天”。
    • 示例:“0 0 10 * * 5#3”在该月的第三个星期五运行该任务。
  • C(Calendar): 指的是月中日星期几字段中使用的日历值。
    • 示例:“0 0 0 5C * *”在该日历中5 号当天或之后的第一天运行该任务。

3. Cron 表达式示例

  • “0 0 9 ? * MON”:在每个星期一的上午 9:00 运行。
  • “0 0 0 1W * *”:在每个月第一个工作日的午夜执行。
  • “0 0 12 1/3 * ?”:计划在该月每 3 天的 1 号下午 12:00 执行。
  • “0 15 10 15 * ?”:在每个月 15 号的上午 10:15 执行。

4. 使用英文名称

星期几月份字段中,您可以使用三个字母的缩写来提高可读性

  • 示例:“0 0 9 ? NOV MON”在 11 月每个星期一的上午 9:00 运行。

5. Spring Scheduling with Cron Expression

在 Spring 中,cron 表达式与 @Scheduled 注解一起使用来调度任务

在带有 @Scheduled 注解的 Spring 应用程序中使用 Cron 表达式

在 Spring 应用程序中,cron 表达式通常与 @Scheduled 注解一起使用,该注解标记用于在运行时按计划执行的方法。 @Scheduled 注解允许通过在 cron 属性中定义 cron 表达式来自动执行重复任务。

在确定要计划的方法后,您可以使用 @Scheduled 注解并在 cron 属性中提供 cron 表达式。 此 cron 表达式定义了方法执行的频率和时间。

示例:带有 @Scheduled 注解的 Spring Scheduling

说明

  • @Scheduled(cron = "15 * * * * *"): cron 表达式“15 * * * * *”表示该方法应在每分钟的第 15 秒运行。
  • scheduledMethod(): 该方法根据提供的 cron 计划执行。
  • LocalDateTime.now(): 显示执行该方法时的当前时间。

关键点

  • cron 表达式“15 * * * * *”表示在每分钟的第 15 秒运行一项任务。
  • 一旦 Spring 应用程序运行,该方法将自动按定义的间隔运行。

此方法广泛用于自动化任务,例如发送定期通知、生成报告或触发批处理作业。

示例:带有 @Scheduled 注解的 Spring Scheduling

Spring 5.3 中的 CronExpression 类

Spring 5.3 引入了 CronExpression 类来处理 cron 表达式。 这个新类取代了已弃用的 CronSequenceGenerator 类,该类基于 Java.util.Calendar 并且存在多个未解决的问题。 Spring 团队决定不解决这些问题,因此他们引入了 CronExpression,它利用了现代 Java.time API。

Spring 5.3 中 CronExpression 的优点

  • 使用现代 Java.time API,与旧的 Java.util.Calendar 相比,它更加强大和功能丰富。
  • 解决了 CronSequenceGenerator 的已知问题。
  • 提供了新功能,并更好地处理了 cron 表达式。

使用 CronExpression 类

要试验 CronExpression 类,您可以使用静态 parse() 方法创建一个实例。 这是一个示例

说明

  • CronExpression.parse(): 此方法解析作为字符串传递的 cron 表达式(在本例中为“15 * * * * *”)。
  • expression.next(): 此方法根据当前的 LocalDateTime 计算下一个有效的执行时间。 它返回与 cron 表达式匹配的下一个执行时间。
  • 示例 cron 表达式(“15 * * * * *”)在每分钟过去的第 15 秒触发。

Spring 5.3 中的 Cron 表达式改进

在 Spring 5.3 中,cron 表达式得到了显着改进,尤其是在引入宏之后。 这些更改使 cron 表达式更易于编写和理解,同时减少了调度任务中的错误。 这些改进在 Spring Boot 2.4 及更高版本中也可用。

Spring 5.3 引入了可以替换常用 cron 表达式的宏,以提高可读性和简洁性。 开发人员可以使用这些宏来节省时间并避免错误,而不是编写复杂的六字段表达式。

这是您可以使用的宏的列表

1. 每年一次

  • 宏: @yearly 或 @annually
  • 等效 "0 0 0 1 1 *"
  • 含义:每年 1 月 1 日午夜。

2. 每月一次

  • 宏: @monthly
  • 等效 "0 0 0 1 * *"
  • 含义:每个月的第一天午夜。

3. 每周一次

  • 宏: @weekly
  • 等效 "0 0 0 * * 0"
  • 含义:每个星期天午夜。

4. 每天一次

  • 宏: @daily 或 @midnight
  • 等效 "0 0 0 * * *"
  • 含义:每天午夜。

5. 每小时一次

  • 宏: @hourly
  • 等效 "0 0 * * * *"
  • 含义:每个小时的开始。

特殊字符的用法

1. 最后几天 (L)

  • 字符 L 代表 last,可用于“月中日”和“星期几”字段。

示例

  • 0 0 0 L * * → 该月的最后一天午夜。
  • 0 0 0 L-2 * * → 该月的倒数第二天午夜。
  • 0 0 0 * * 4L → 该月的最后一个星期四午夜。
  • 0 0 0 * * MONL → 该月的最后一个星期一午夜。

2. 工作日 (W)

  • 字符 W 代表 Weekdays,在“月中日”字段中使用,表示特定日期最近的工作日。

示例

  • 0 0 0 1W * * → 该月的第一个工作日午夜。
  • 0 0 0 LW * * → 该月的最后一个工作日午夜。

3. 月中的星期几 (#)

  • # 字符指定该月中特定日期的第 n 次出现。 它仅适用于“星期几”字段。

示例

  • 0 0 0 ? * 5#3 → 该月的第三个星期五午夜。
  • 0 0 0 ? * SUN#1 → 该月的第一个星期日午夜。