Spring 5.3 新特性:改进的 Cron 表达式

工程技术 | Arjen Poutsma | 2020年11月10日 | ...

如果您经常收听A Bootiful Podcast,您可能已经听说过我们对 Spring Framework Cron 支持所做的改进。Cron 表达式在 Spring 应用中主要通过@Scheduled 注解使用。在 Spring 5.3 中,我们引入了CronExpression 类,顾名思义,它代表一个cron 表达式

CronExpression 替代了 CronSequenceGenerator,后者基于 java.util.Calendar,存在一些已知的 Spring 团队成员都不愿解决的问题。引入新的类型使得我们可以使用更优秀的 java.time API,解决了悬而未决的问题,并且(希望)也引入了新功能。虽然 Spring 通常偏爱保持向后兼容,但有时我们确实认为从零开始是最佳选择。

用法

自 Spring Framework 5.3 起,您通常使用 @Scheduled 注解创建 cron 触发器,它内部使用了 CronExpression。这意味着如果您使用的是该版本,您就可以开始使用新功能了。

如果您想自己尝试使用 CronExpression,可以通过静态的 parse 方法创建一个

var expression = CronExpression.parse("10 * * * * *");
var result = expression.next(LocalDateTime.now());
System.out.println(result);

在这个例子中,expression 表示一个 cron 序列,它在每分钟的第 10 秒触发。parse 方法接受一个包含六个空格分隔的时间和日期字段的众所周知的字符串

┌───────────── 秒 (0-59) │ ┌───────────── 分钟 (0 - 59) │ │ ┌───────────── 小时 (0 - 23) │ │ │ ┌───────────── 月份中的日期 (1 - 31) │ │ │ │ ┌───────────── 月份 (1 - 12) (或 JAN-DEC) │ │ │ │ │ ┌───────────── 星期几 (0 - 7) │ │ │ │ │ │ (或 MON-SUN -- 0 或 7 是星期日) │ │ │ │ │ │ * * * * * *

适用以下规则

  • 字段可以是星号 (*),它始终代表“第一个-最后一个”。对于月份中的日期或星期几字段,可以使用问号 (?) 代替星号。

  • 逗号 (,) 用于分隔列表中的项。

  • 两个数字用连字符 (-) 分隔表示一个范围。指定的范围是包含的。

  • 在范围(或 *)后使用 / 指定在该范围内数字值的间隔。

  • 星期几和月份字段也可以使用英文名称。使用特定日期或月份的前三个字母(不区分大小写)。

以下是一些示例

Cron 表达式

含义

0 0 * * * *

每天的每小时的顶部(整点)

*/10 * * * * *

每十秒钟

0 0 8-10 * * *

每天的 8、9 和 10 点

0 0 6,19 * * *

每天的上午 6:00 和下午 7:00

0 0/30 8-10 * * *

每天的 8:00、8:30、9:00、9:30、10:00 和 10:30

0 0 9-17 * * MON-FRI

工作日九点到五点的整点

0 0 0 25 12 ?

每年圣诞节的午夜

next 方法返回触发器的下一次出现时间,如果没有则返回 null。它接受一个 java.time.temporal.Temporal 作为参数,这意味着它不仅接受 LocalDateTime,如果涉及时区,也接受 ZonedDateTime

新功能

使用 java.time API 让我们能够引入几个新功能,使 Spring 对 cron 表达式的支持与其他调度器处于同等地位。从 Spring Framework 5.3 开始,您可以在 @Scheduled 中使用这些功能。

诸如 0 0 * * * * 之类的表达式对于人类来说很难解析,因此在出现错误时难以修复。为了提高可读性,Spring 现在支持以下宏,它们代表常用的序列。您可以使用这些宏代替六位数字的值,例如:@Scheduled(cron = "@hourly")

含义

@yearly (或 @annually)

每年一次 (0 0 0 1 1 *)

@monthly

每月一次 (0 0 0 1 * *)

@weekly

每周一次 (0 0 0 * * 0)

@daily (或 @midnight)

每天一次 (0 0 0 * * *),或者

@hourly

每小时一次 (0 0 * * * *)

最后几天

月份中的日期和星期几字段可以包含字符 L,它在不同字段中含义不同。在月份中的日期字段中,L 代表该月的最后一天。如果后面跟着负偏移量(即 L-n),则表示该月的倒数第 n

在星期几字段中,L 代表该周的最后一天。如果在前面加上数字或三个字母的名称(dLDDDL),则表示该月最后一周的星期几(dDDD

以下是一些示例

Cron 表达式

含义

0 0 0 L * *

该月的最后一天午夜

0 0 0 L-3 * *

该月的倒数第三天午夜

0 0 0 * * 5L

该月的最后一个星期五午夜

0 0 0 * * THUL

该月的最后一个星期四午夜

工作日

月份中的日期字段可以是 nW,它代表最接近该月第 n 天的工作日。如果 n 落在一个星期六,则结果是之前的星期五。如果 n 落在一个星期日,则结果是之后的星期一,当 n1 并落在一个星期六时也是如此(即:1W 代表该月的第一个工作日)。

如果月份中的日期字段是 LW,则表示该月的最后一个工作日

以下是一些示例

Cron 表达式

含义

0 0 0 1W * *

该月的第一个工作日午夜

0 0 0 LW * *

该月的最后一个工作日午夜

该月的第二个星期五

星期几字段可以是 d#n (或 DDD#n),它代表该月第 n 个星期几(dDDD

以下是一些示例

Cron 表达式

含义

0 0 0 ? * 5#2

该月第二个星期五午夜

0 0 0 ? * MON#1

该月第一个星期一午夜

改进的 cron 表达式支持只是 Spring Framework 5.3 提供的众多功能之一,并将作为即将发布的Spring Boot 2.4 的一部分。

获取 Spring 新闻通讯

订阅 Spring 新闻通讯,保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获取支持

Tanzu Spring 在一个简单的订阅中提供了对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举办的活动

查看 Spring 社区所有即将举办的活动。

查看所有