• Spring Boot 写定时任务,发现了一个大坑!


    最近栈长用 Spring Boot 写了一个定时任务:

    @Scheduled(cron = "0/10 * * * * ? *")
    public void execute() {
    	...
    }
    

    Spring Boot 实现定时任务确实很简单,其实是从 Spring 3.1 开始,定时任务的编写就变得非常简单,只需要几个注解就能快速开启计划任务的支持,具体可以看这篇文章:https://mp.weixin.qq.com/s/hsuCC93OJFc8URI517-umg

    可是当我把代码写完,启动就报错:

    Caused by: java.lang.IllegalStateException: Encountered invalid @Scheduled method 'xxx': Cron expression must consist of 6 fields (found 7 in "0/10 * * * * ? *")
    	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.processScheduled(ScheduledAnnotationBeanPostProcessor.java:511) ~[spring-context-5.3.1.jar:5.3.1]
    	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.lambda$null$1(ScheduledAnnotationBeanPostProcessor.java:374) ~[spring-context-5.3.1.jar:5.3.1]
    	at java.lang.Iterable.forEach(Iterable.java:75) ~[na:1.8.0_261]
    	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.lambda$postProcessAfterInitialization$2(ScheduledAnnotationBeanPostProcessor.java:374) ~[spring-context-5.3.1.jar:5.3.1]
    	at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[na:1.8.0_261]
    	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.postProcessAfterInitialization(ScheduledAnnotationBeanPostProcessor.java:373) ~[spring-context-5.3.1.jar:5.3.1]
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:444) ~[spring-beans-5.3.1.jar:5.3.1]
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1792) ~[spring-beans-5.3.1.jar:5.3.1]
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:609) ~[spring-beans-5.3.1.jar:5.3.1]
    	... 16 common frames omitted
    

    什么鬼?

    错误描述大概是说我的 Cron 表达式有问题,Cron 表达式只能由 6 位组成,但我的表达式有 7 位,不能啊,表达式也确实没问题的啊。。。

    点进去看下 @Scheduled 注解的 cron 参数源码:

    确实只有 6 位,并没有表示年份的占位。

    继续看源码,CronSequenceGenerator 在 Spring 5.3 中已经标识废弃了,需要转到:

    org.springframework.scheduling.support.CronExpression

    再点进去看 CronExpression 类的源码:

    6 个字段的意思很清楚了,具体可以参考:

    https://www.manpagez.com/man/5/crontab/

    示例表达式:

    "0 0 * * * *" = the top of every hour of every day.
    "*/10 * * * * *" = every ten seconds.
    "0 0 8-10 * * *" = 8, 9 and 10 o'clock of every day.
    "0 0 6,19 * * *" = 6:00 AM and 7:00 PM every day.
    "0 0/30 8-10 * * *" = 8:00, 8:30, 9:00, 9:30, 10:00 and 10:30 every day.
    "0 0 9-17 * * MON-FRI" = on the hour nine-to-five weekdays
    "0 0 0 25 12 ?" = every Christmas Day at midnight
    "0 0 0 L * *" = last day of the month at midnight
    "0 0 0 L-3 * *" = third-to-last day of the month at midnight
    "0 0 0 1W * *" = first weekday of the month at midnight
    "0 0 0 LW * *" = last weekday of the month at midnight
    "0 0 0 * * 5L" = last Friday of the month at midnight
    "0 0 0 * * THUL" = last Thursday of the month at midnight
    "0 0 0 ? * 5#2" = the second Friday in the month at midnight
    "0 0 0 ? * MON#1" = the first Monday in the month at midnight
    

    并且支持以下代替写法:

    "@yearly" (or "@annually") to run un once a year, i.e. "0 0 0 1 1 *",
    "@monthly" to run once a month, i.e. "0 0 0 1 * *",
    "@weekly" to run once a week, i.e. "0 0 0 * * 0",
    "@daily" (or "@midnight") to run once a day, i.e. "0 0 0 * * *",
    "@hourly" to run once an hour, i.e. "0 0 * * * *".
    

    如:每年:0 0 0 1 1 *,就可以写成:@yearly,除了每年,还有每月、每月、每周、每天、每小时,可惜……没有每分、每秒!

    Spring Task 我们可以将它看成是一个轻量级的 Quartz,而且使用起来比 Quartz 要简单许多,使用了类似于 cron 的表达式,并扩展了平常的 UN*X 定义,看来和平常的 cron 表达式还不太一样,位数不同,也存在兼容问题,真坑。。。

    既然知道了问题所在,再回到之前错误,那就只能把最后的表示 "年" 的字段去掉,6 位就够了,第7 位不要,默认就是表示每年。

    那么问题来了,我想在具体的某年,如 2025/02/25 这天执行任务,咋整?

    没办法,Spring Task 不能指定年份,那就只能换成 Quartz,Quartz 也更强大,所以,如果是简单的定时任务,Spring Task 就搞定了,复杂的建议还是使用 Quartz。

    另外,注意,Spring Task 的 cron 表达式并不是完全兼容通常的 cron 表达式,最好根据以上官方的文档来编写,以免到了线上不执行那就完蛋了。

    最后,觉得我的文章对你用收获的话,动动小手,给个在看、转发,原创不易,栈长需要你的鼓励。

    版权申明:本文系公众号 "Java技术栈" 原创,原创实属不易,转载、引用本文内容请注明出处,禁止抄袭、洗稿,请自重,尊重他人劳动成果和知识产权。

    近期热文推荐:

    1.1,000+ 道 Java面试题及答案整理(2021最新版)

    2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!

    3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!

    4.Spring Cloud 2020.0.0 正式发布,全新颠覆性版本!

    5.《Java开发手册(嵩山版)》最新发布,速速下载!

    觉得不错,别忘了随手点赞+转发哦!

  • 相关阅读:
    最新美丽说网购平台模板
    红色的原油投资金融专题模板
    简单响应式Bootstrap框架中文官网页面模板
    蓝色简约的工业大学学校网站静态模板
    红色经典招生校园网站全套
    白色简洁的瑞班克个人博客网站
    仿360影视网站模板html
    红色的企业新闻门户网站模板
    橙色的汽车蚂蚁企业门户网站模板
    使用ExtJS做一个用户的增删改查
  • 原文地址:https://www.cnblogs.com/javastack/p/14890629.html
Copyright © 2020-2023  润新知