SpringBoot?@Scheduled?Cron表達(dá)式使用方式
Cron 表達(dá)式詳解
Cron 表達(dá)式是用于定義定時任務(wù)執(zhí)行時間的字符串,廣泛應(yīng)用于 Spring 的 @Scheduled、Quartz 等定時任務(wù)框架。
其核心是通過 時間字段 和 通配符 組合實現(xiàn)復(fù)雜的調(diào)度規(guī)則。
1. 表達(dá)式格式
Cron 表達(dá)式由 6或7個字段 組成,分別表示不同時間單位(Spring 中通常用 6位 格式)。
格式如下:
字段 | 允許值 | 特殊字符 | 說明 |
---|---|---|---|
秒(Seconds) | 0-59 | , - * / | 可精確到秒級調(diào)度 |
分(Minutes) | 0-59 | , - * / | |
小時(Hours) | 0-23 | , - * / | |
日(Day) | 1-31 | , - * / ? L W | 月份中的某一天 |
月(Month) | 1-12 或 JAN-DEC | , - * / | |
周(Week) | 0-7 或 SUN-SAT (0=周日) | , - * / ? L # | 周幾(1=MON, 7=SUN) |
年(Year) | 1970-2099 (可選) | , - * / | Spring 中通常省略 |
2. 特殊字符解析
符號 | 作用 | 示例 |
---|---|---|
* | 匹配任意值 | 0 * * * * ? 每分鐘的0秒執(zhí)行 |
? | 僅在 日 或 周 字段使用,表示“無意義” | 0 0 0 * * ? 每天0點(diǎn)執(zhí)行 |
- | 范圍區(qū)間 | 0 0 10-12 * * ? 10-12點(diǎn)每小時執(zhí)行 |
, | 多個值 | 0 0 2,14 * * ? 每天2點(diǎn)和14點(diǎn)執(zhí)行 |
/ | 步長(間隔時間) | 0 0/5 * * * ? 每隔5分鐘執(zhí)行 |
L | 最后一天(僅 日 或 周 字段) | 0 0 L * * ? 每月最后一天0點(diǎn)執(zhí)行 |
W | 最近工作日(僅 日 字段) | 0 0 0 15W * ? 每月15日最近的工作日執(zhí)行 |
# | 指定月份的周幾(僅 周 字段) | 0 0 0 ? * 6#3 每月第3個周五執(zhí)行 |
3. 常用示例
表達(dá)式 | 說明 |
---|---|
0 0 12 * * ? | 每天中午12點(diǎn)執(zhí)行 |
0 0/5 14 * * ? | 每天下午2點(diǎn)開始,每隔5分鐘執(zhí)行一次 |
0 15 10 ? * MON-FRI | 每周一至周五上午10:15執(zhí)行 |
0 0 0 1 1 ? 2024 | 2024年1月1日0點(diǎn)執(zhí)行(需7位表達(dá)式) |
0 0 8-18/2 ? * MON | 每周一上午8點(diǎn)到下午6點(diǎn),每隔2小時執(zhí)行一次 |
0 0 0 L * ? | 每月最后一天的0點(diǎn)執(zhí)行 |
0 0 0 15W * ? | 每月15日最近的工作日執(zhí)行 |
0 0 0 ? * 6#3 | 每月第3個周五0點(diǎn)執(zhí)行 |
4. 重點(diǎn)規(guī)則
1. 日與周的互斥性
- 若同時指定 日 和 周,需用 ? 忽略其中一個字段。
- ? 正確:0 0 0 ? * MON(每周一執(zhí)行,忽略日)
- ? 錯誤:0 0 0 * * MON(日和周同時生效,可能沖突)
2. 月份和星期的縮寫
- 月份:JAN, FEB, MAR… DEC
- 星期:SUN, MON, TUE… SAT
- L 和 W 的組合
- LW 表示當(dāng)月的最后一個工作日。
- L-3 表示倒數(shù)第3天。
- 年份字段(可選)
- Spring 的 @Scheduled 不支持年份字段,需用6位表達(dá)式。
5. 動態(tài)與復(fù)雜場景
1. 動態(tài) Cron 表達(dá)式
- Spring 中可通過 @Scheduled(cron = “${cron.expression}”) 從配置文件讀取。
- 結(jié)合數(shù)據(jù)庫動態(tài)更新任務(wù):
@Scheduled(cron = "#{@cronService.getCronExpression()}") public void dynamicTask() { // 業(yè)務(wù)邏輯 }
2. 避開整點(diǎn)任務(wù)高峰
- 添加隨機(jī)延遲(避免多個任務(wù)同時觸發(fā)):
@Scheduled(cron = "0 #{T(java.util.concurrent.ThreadLocalRandom).current().nextInt(55)} * * * ?") public void randomMinuteTask() { // 每小時隨機(jī)分鐘執(zhí)行 }
3. 閏年處理
- Cron 無法直接處理閏年,需結(jié)合代碼邏輯判斷。
6. 調(diào)試與驗證
1. 在線工具
- Crontab Guru:快速驗證表達(dá)式。
- CronMaker:生成表達(dá)式并查看下次執(zhí)行時間。
- 日志調(diào)試
- 在任務(wù)方法中添加日志,觀察觸發(fā)時間是否符合預(yù)期:
@Scheduled(cron = "0 0/5 * * * ?") public void logTask() { log.info("任務(wù)執(zhí)行時間: {}", LocalDateTime.now()); }
7. 常見問題
1. 為什么任務(wù)沒有執(zhí)行?
- 檢查是否添加
@EnableScheduling
。 - 檢查 Cron 表達(dá)式是否正確(如 Spring 不支持年份字段)。
- 檢查時區(qū)設(shè)置(默認(rèn)使用服務(wù)器時區(qū),可通過 zone 屬性修改)。
2. 如何實現(xiàn)每隔 N 天執(zhí)行?
方案1
:使用0 0 0 */N * ?
(如0 0 0 */5 * ?
每隔5天執(zhí)行)。方案2
:通過代碼記錄上一次執(zhí)行時間。
3. 分布式環(huán)境下的冪等性
使用 Redis 分布式鎖:
@Scheduled(cron = "0 0 * * * ?") public void distributedTask() { if (redisLock.tryLock("taskLock", 10)) { try { // 業(yè)務(wù)邏輯 } finally { redisLock.unlock("taskLock"); } } }
總結(jié)
Cron 表達(dá)式通過簡潔的語法實現(xiàn)了靈活的定時規(guī)則,但需注意 字段互斥性 和 特殊字符的適用場景。
在復(fù)雜業(yè)務(wù)中,可結(jié)合動態(tài)配置、分布式鎖和日志監(jiān)控來確保任務(wù)穩(wěn)定執(zhí)行。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot 項目使用jasypt加密數(shù)據(jù)源的方法
Jasypt 是一個 Java 庫,它允許開發(fā)者以最小的努力為他/她的項目添加基本的加密功能,而且不需要對密碼學(xué)的工作原理有深刻的了解。接下來通過本文給大家介紹springboot 項目使用jasypt加密數(shù)據(jù)源的問題,一起看看吧2021-11-11Java雙向鏈表按照順序添加節(jié)點(diǎn)的方法實例
這篇文章主要給大家介紹了關(guān)于Java雙向鏈表按照順序添加節(jié)點(diǎn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02Eclipse使用maven搭建spring mvc圖文教程
這篇文章主要為大家分享了Eclipse使用maven搭建spring mvc圖文教程,感興趣的小伙伴們可以參考一下2016-05-05SpringBoot SSO輕松實現(xiàn)(附demo)
這篇文章主要介紹了SpringBoot SSO輕松實現(xiàn)(附demo),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01RandomAccessFile簡介_動力節(jié)點(diǎn)Java學(xué)院整理
RandomAccessFile 是隨機(jī)訪問文件(包括讀/寫)的類。它支持對文件隨機(jī)訪問的讀取和寫入,即我們可以從指定的位置讀取/寫入文件數(shù)據(jù)。這篇文章主要介紹了RandomAccessFile簡介,需要的朋友可以參考下2017-05-05