领先一步
VMware 提供培训和认证,助您加速进步。
了解更多如果您经常收听 A Bootiful Podcast,您可能已经听说过我们对 Spring Framework 的 cron 支持所做的改进。Cron 表达式主要通过 @Scheduled 注解在 Spring 应用程序中使用。在 Spring 5.3 中,我们引入了 CronExpression 类,它代表——您猜对了——一个 cron 表达式。
CronExpression 替代了 CronSequenceGenerator,后者基于 java.util.Calendar 并且存在一些已知问题,Spring 团队成员都不太愿意解决这些问题。引入新类型使我们能够使用更优越的 java.time API,解决现有问题,并(希望能)引入新功能。虽然 Spring 通常倾向于保持向后兼容,但有时我们确实认为从头开始是最佳选择。
从 Spring Framework 5.3 开始,你通常使用 @Scheduled 注解创建 cron 触发器,该注解内部使用 CronExpression。这意味着如果你使用的是该版本,你已经可以开始使用新功能。
如果你想自己使用 CronExpression,可以通过静态解析方法创建一个
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 * * * * 这样的表达式对人类来说很难解析,因此在出现 bug 时很难修复。为了提高可读性,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 表示该周的最后一天。如果前缀为数字或三个字母的名称(dL 或 DDDL),则表示该月中的星期几(d 或 DDD)的最后一天。
以下是一些示例
Cron 表达式
含义
0 0 0 L * *
每月最后一天的午夜
0 0 0 L-3 * *
每月倒数第三天的午夜
0 0 0 * * 5L
每月最后一个星期五的午夜
0 0 0 * * THUL
每月最后一个星期四的午夜
月份中的日期字段可以是 nW,它表示离该月第 n 天最近的工作日。如果 n 落在星期六,则表示它之前的星期五。如果 n 落在星期日,则表示它之后的星期一,如果 n 是 1 并且落在星期六(即:1W 表示该月的第一个工作日),也会发生这种情况。
如果月份中的日期字段是 LW,则表示该月的最后一个工作日。
以下是一些示例
Cron 表达式
含义
0 0 0 1W * *
每月第一个工作日的午夜
0 0 0 LW * *
每月最后一个工作日的午夜
星期几字段可以是 d#n (或 DDD#n),它表示该月中的第 n 个星期 d (或 DDD)。
以下是一些示例
Cron 表达式
含义
0 0 0 ? * 5#2
该月第二个星期五的午夜
0 0 0 ? * MON#1
该月第一个星期一的午夜
改进的 cron 表达式支持只是 Spring Framework 5.3 提供的众多功能之一,并且将成为即将发布的Spring Boot 2.4 版本的一部分。