SpringBoot 定时任务

可参考文档 https://pdai.tech/md/develop/cron/dev-cron-x-usage.html

CRON

CRON 表达式

Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:

Seconds Minutes Hours DayofMonth Month DayofWeek Year

Seconds Minutes Hours DayofMonth Month DayofWeek

CRON 表达式的结构

Cron表达式是一个具有时间含义的字符串,字符串以5个空格隔开,分为6个域,格式为X X X X X X。其中X是一个域的占位符。单个域有多个取值时,使用半角逗号,隔开取值。每个域可以是确定的取值,也可以是具有逻辑意义的特殊字符。

域取值

是否必须 取值范围 特殊字符
秒 Seconds [0, 59] *,-/
分钟 Minutes [0, 59] *,-/
小时 Hours [0, 23] *,-/
日期 DayofMonth [1, 31] *,-/? L W
月份 Month [1, 12][JAN, DEC] *,-/
星期 DayofWeek [1, 7][MON, SUN]。 若使用 [1, 7] 表达式,1 代表星期一,7代表星期日 *,-/? L #
年 Year 1970+ -*/

特殊字符

Seconds Minutes Hours DayofMonth Month DayofWeek

特殊字符 含义 示例
* 匹配任意值。 在字段中,*表示每个月。
, 列出枚举值。 在字段分钟中,5,20表示分别在5分钟和20分钟触发一次。
- 指定范围。 在字段分钟中,5-20表示从5分钟到20分钟之间每隔一分钟触发一次。
/ 指定数值的增量。 在字段分钟中,0/15表示从第0分钟开始,每15分钟。在字段分钟3/20表示从第3分钟开始,每20分钟。
? 不指定值,仅用于日期和星期。 当字段日期星期其中之一被指定了值以后,即 DayofMonthDayOfWeek,为了避免冲突,需要将另一个字段的值设为?
L 单词Last的首字母,表示最后一天,仅字段日期星期支持该字符。重要 指定L字符时,避免指定列表或范围,否则会导致逻辑问题。 在字段日期中,L表示某个月的最后一天。在字段星期中,L表示一个星期的最后一天,也就是星期日(SUN)。如果在L前有具体的内容,例如,在字段星期中的6L表示这个月的最后一个星期六。
W 除周末以外的有效工作日,在离指定日期的最近的有效工作日触发事件。W字符寻找最近有效工作日时不会跨过当前月份,连用字符LW时表示为指定月份的最后一个工作日。 在字段日期5W,如果5日是星期六,则将在最近的工作日星期五,即4日触发。如果5日是星期天,则将在最近的工作日星期一,即6日触发;如果5日在星期一到星期五中的一天,则就在5日触发。
# 确定每个月的第几个星期几。重要 仅字段星期支持该字符。 在字段星期中,4#2表示某月的第二个星期四。

L,避免且不能指定列表或范围,否则无效。比如 0 0 0 1-10,L * ? 不能即是每月的 1-10 号又是每月的最后一天,会出现歧义。也就是说,他不能和 , 或者 - 连用,只能单独使用。

如果你想表达每月的 1-10 号加上每月最后一天,那么只能是写两个 CRON 表达式。

常用表达式例子

定时任务

在主程序类上加上 @EnableScheduling,会去自动扫描带有 @Scheduled 注解的定时任务

java 复制代码
@SpringBootApplication
@EnableScheduling
public class StudyApplication {

    public static void main(String[] args) {
        SpringApplication.run(StudyApplication.class, args);
    }

}

此处,就会开启一个定时任务,注意,需要在类上加上 @Component 组件

java 复制代码
@Component
public class ScheduledTask {

    @Scheduled(fixedRate =  3000)
    public void scheduledTask() {
        System.out.println("time: " + LocalDateTime.now());
    }
}

fixedRate 是 long 类型,表示任务执行的间隔毫秒数,上述代码每3秒执行一次

@Scheduled

对于 @Scheduled 的使用可以总结如下

  • @Scheduled(fixedRate = 3000) :上一次开始执行时间点之后 3 秒再执行

    fixedRate 表示每次任务开始执行时,至少要等待指定的时间间隔才会开始下次执行。也就是说,每次任务开始时会按固定的时间间隔进行触发,而不考虑任务执行的实际耗时。

    • 在上次执行开始之后,按指定的间隔时间执行下次任务。
    • 任务执行时间不会影响到下次任务的触发,任务可能会在上一个任务还没执行完时开始执行。
  • @Scheduled(fixedDelay = 3000) :上一次执行完毕时间点之后 3 秒再执行

    fixedDelay 表示任务执行完毕后,会等待指定的时间间隔再执行下次任务。也就是说,每次任务的间隔时间是从任务 结束 的时间点开始计算。

    • 每次任务执行完后,等待指定的间隔时间,再开始执行下一次任务。
    • 任务执行时间会影响到下一次任务的触发时间,确保任务之间有固定的延迟。
  • @Scheduled(initialDelay = 1000, fixedRate = 3000)

    第一次延迟1秒后执行,之后按fixedRate的规则每 3 秒执行一次

    initialDelay 设置的是任务第一次执行的延迟时间。在任务启动时,任务会先等待 initialDelay 指定的时间,然后开始第一次执行。initialDelay 配合 fixedRatefixedDelay

    • initialDelay 设置任务的首次执行的延迟时间。
    • 只影响第一次执行,后续的执行间隔由 fixedRatefixedDelay 决定。
  • @Scheduled(cron="0 0 2 1 * ? *") :通过cron表达式定义规则