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 正式釋出,全新顛覆性版本!
覺得不錯,別忘了隨手點贊+轉發哦!