Java定時(shí)任務(wù)Schedule的基本用法及Cron表達(dá)式實(shí)踐記錄
在日常Java開發(fā)中,定時(shí)任務(wù)是高頻需求場(chǎng)景,比如定時(shí)同步數(shù)據(jù)、定時(shí)清理日志、定時(shí)發(fā)送通知等。Spring框架提供的@Scheduled注解簡(jiǎn)化了定時(shí)任務(wù)的開發(fā),無(wú)需依賴外部調(diào)度框架(如Quartz),就能快速實(shí)現(xiàn)輕量級(jí)定時(shí)任務(wù)。而cron表達(dá)式作為Schedule中靈活度最高的觸發(fā)規(guī)則配置方式,是掌握該功能的核心。本文將從Schedule的基礎(chǔ)用法入手,深入解析cron表達(dá)式,并結(jié)合實(shí)例演示其在項(xiàng)目中的應(yīng)用。
一、Spring Schedule基礎(chǔ)配置
要使用Spring Schedule,首先需要完成基礎(chǔ)配置,整體步驟簡(jiǎn)單易懂,適用于Spring Boot項(xiàng)目和傳統(tǒng)Spring項(xiàng)目。
1.1 依賴引入(Spring Boot)
Spring Boot項(xiàng)目無(wú)需額外引入依賴,spring-boot-starter中已包含Schedule相關(guān)組件,只需確保pom.xml(Maven)中存在核心依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>1.2 開啟定時(shí)任務(wù)支持
在Spring Boot啟動(dòng)類上添加@EnableScheduling注解,開啟定時(shí)任務(wù)調(diào)度功能:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling // 開啟定時(shí)任務(wù)
public class ScheduleDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduleDemoApplication.class, args);
}
}1.3 基礎(chǔ)定時(shí)任務(wù)實(shí)現(xiàn)
通過(guò)@Scheduled注解標(biāo)記方法為定時(shí)任務(wù),支持多種觸發(fā)規(guī)則,常見的有固定延遲、固定頻率和cron表達(dá)式三種方式。其中cron表達(dá)式適用于復(fù)雜的時(shí)間規(guī)則配置,也是本文重點(diǎn)。
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component // 交給Spring管理
public class ScheduleTask {
// 固定延遲:上一次任務(wù)執(zhí)行完畢后延遲1秒執(zhí)行下一次
@Scheduled(fixedDelay = 1000)
public void fixedDelayTask() {
System.out.println("固定延遲任務(wù)執(zhí)行:" + System.currentTimeMillis());
}
// 固定頻率:每隔1秒執(zhí)行一次(無(wú)論上一次是否完成)
@Scheduled(fixedRate = 1000)
public void fixedRateTask() {
System.out.println("固定頻率任務(wù)執(zhí)行:" + System.currentTimeMillis());
}
// cron表達(dá)式:每天凌晨2點(diǎn)執(zhí)行
@Scheduled(cron = "0 0 2 * * ?")
public void cronTask() {
System.out.println("Cron任務(wù)執(zhí)行:" + System.currentTimeMillis());
}
}二、Cron表達(dá)式深度解析
Cron表達(dá)式是一種時(shí)間表達(dá)式,用于定義復(fù)雜的定時(shí)規(guī)則,起源于Unix系統(tǒng),后被廣泛應(yīng)用于各類調(diào)度框架。在Spring Schedule中,cron表達(dá)式支持6個(gè)或7個(gè)字段,字段之間用空格分隔,語(yǔ)法格式如下:
2.1 表達(dá)式格式
Spring Schedule中的cron表達(dá)式格式(7個(gè)字段,最后一個(gè)年份字段可選):
秒 分 時(shí) 日 月 周 年(可選)
各字段的取值范圍及允許的特殊字符如下表所示:
字段 | 取值范圍 | 允許的特殊字符 | 說(shuō)明 |
|---|---|---|---|
秒 | 0-59 | , - * / | 每秒用*表示,每5秒用0/5表示 |
分 | 0-59 | , - * / | 每分用*表示,每10分用0/10表示 |
時(shí) | 0-23 | , - * / | 每天凌晨2點(diǎn)用2表示,每6小時(shí)用0/6表示 |
日 | 1-31 | , - * / ? L W C | ?表示不指定值,避免日和周沖突;L表示當(dāng)月最后一天 |
月 | 1-12 或 JAN-DEC | , - * / | 1表示1月,JAN也可表示1月 |
周 | 1-7 或 SUN-SAT | , - * / ? L C # | 1表示周日,7表示周六;#表示第幾個(gè)周幾,如6#3表示當(dāng)月第3個(gè)周五 |
年(可選) | 1970-2099 | , - * / | 省略時(shí)表示所有年份 |
2.2 特殊字符含義
cron表達(dá)式的靈活度依賴于特殊字符的使用,核心特殊字符的含義如下:
- *:表示匹配該字段的所有值。例如,時(shí)字段為*,表示每小時(shí)都觸發(fā)。
- ?:僅用于日和周字段,標(biāo)識(shí)不指定具體值,避免兩個(gè)字段沖突。例如,要指定每月10號(hào)觸發(fā),周字段需設(shè)為?
- /:表示遞增觸發(fā)。格式為“起始值/步長(zhǎng)”,例如,秒字段為0/5,表示從0秒開始,每5秒觸發(fā)一次。
- -:表示區(qū)間。例如,時(shí)字段為9-17,表示上午9點(diǎn)到下午5點(diǎn)之間,每小時(shí)觸發(fā)一次。
- ,:表示多個(gè)值。例如,分字段為10,20,30,表示每小時(shí)的10分、20分、30分各觸發(fā)一次。
- L:僅用于日和周字段,標(biāo)識(shí)最后一個(gè)。例如,日字段為L(zhǎng),表示當(dāng)月最后一天;周字段為L(zhǎng),表示當(dāng)月最后一個(gè)周六。
- #:僅用于周字段,標(biāo)識(shí)第幾個(gè)周幾。格式為“周幾#第幾個(gè)”,例如,周字段為6#3,表示當(dāng)月第3個(gè)周五(6表示周五)。
2.3 常用Cron表達(dá)式示例
結(jié)合實(shí)際業(yè)務(wù)場(chǎng)景,整理以下常用cron表達(dá)式,可直接套用:
- 0 0 2 * * ?:每天凌晨2點(diǎn)執(zhí)行
- 0 30 8 * * ?:每天早上8點(diǎn)30分執(zhí)行
- 0 0/10 * * * ?:每10分鐘執(zhí)行一次
- 0 0 9-18 * * ?:每天上午9點(diǎn)到下午6點(diǎn),每小時(shí)執(zhí)行一次
- 0 0 12 ? * SAT:每周六中午12點(diǎn)執(zhí)行
- 0 0 0 L * ?:每月最后一天凌晨0點(diǎn)執(zhí)行
- 0 0 0 1 * ?:每月1號(hào)凌晨0點(diǎn)執(zhí)行
- 0 0 0 ? * 6#1:每月第一個(gè)周五凌晨0點(diǎn)執(zhí)行
- 0/5 * * * * ?:每5秒執(zhí)行一次(用于測(cè)試)
三、Schedule進(jìn)階用法與注意事項(xiàng)
3.1 異步定時(shí)任務(wù)
默認(rèn)情況下,Spring Schedule的定時(shí)任務(wù)是同步執(zhí)行的,即多個(gè)任務(wù)會(huì)在同一個(gè)線程中按順序執(zhí)行,若某個(gè)任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng),會(huì)阻塞其他任務(wù)。如需異步執(zhí)行,可通過(guò)@EnableAsync和@Async注解實(shí)現(xiàn):
// 1. 啟動(dòng)類添加@EnableAsync開啟異步支持
@SpringBootApplication
@EnableScheduling
@EnableAsync
public class ScheduleDemoApplication { ... }
// 2. 定時(shí)任務(wù)方法添加@Async注解
@Component
public class ScheduleTask {
@Async
@Scheduled(cron = "0/5 * * * * ?")
public void asyncCronTask() {
System.out.println("異步Cron任務(wù)執(zhí)行:" + Thread.currentThread().getName());
}
}3.2 動(dòng)態(tài)調(diào)整Cron表達(dá)式
靜態(tài)cron表達(dá)式在項(xiàng)目啟動(dòng)后無(wú)法修改,若需動(dòng)態(tài)調(diào)整觸發(fā)規(guī)則,可通過(guò)實(shí)現(xiàn)SchedulingConfigurer接口自定義調(diào)度配置,從數(shù)據(jù)庫(kù)或配置中心讀取cron表達(dá)式:
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
@Component
public class DynamicCronTask implements SchedulingConfigurer {
// 模擬從數(shù)據(jù)庫(kù)獲取cron表達(dá)式(實(shí)際項(xiàng)目中可對(duì)接DB或Nacos)
private String cron = "0/5 * * * * ?";
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// 注冊(cè)定時(shí)任務(wù)
taskRegistrar.addTriggerTask(
this::dynamicTaskExecute, // 任務(wù)執(zhí)行邏輯
triggerContext -> {
// 每次觸發(fā)前重新獲取cron表達(dá)式(實(shí)現(xiàn)動(dòng)態(tài)更新)
CronTrigger trigger = new CronTrigger(getCron());
return trigger.nextExecutionTime(triggerContext);
}
);
}
public void dynamicTaskExecute() {
System.out.println("動(dòng)態(tài)Cron任務(wù)執(zhí)行:" + System.currentTimeMillis());
}
// 獲取最新cron表達(dá)式(可擴(kuò)展為從數(shù)據(jù)庫(kù)查詢)
public String getCron() {
return this.cron;
}
// 更新cron表達(dá)式
public void setCron(String cron) {
this.cron = cron;
}
}3.3 核心注意事項(xiàng)
- 日和周字段沖突:日和周字段不能同時(shí)指定具體值,需有一個(gè)設(shè)為?,否則會(huì)導(dǎo)致任務(wù)觸發(fā)規(guī)則異常。例如,要指定每月10號(hào)執(zhí)行,周字段必須設(shè)為?,表達(dá)式為0 0 0 10 * ?。
- 任務(wù)執(zhí)行時(shí)長(zhǎng):同步任務(wù)中,若任務(wù)執(zhí)行時(shí)長(zhǎng)超過(guò)觸發(fā)間隔,下一次任務(wù)會(huì)等待上一次完成后再執(zhí)行;異步任務(wù)無(wú)此限制,但需注意并發(fā)問(wèn)題。
- 時(shí)區(qū)問(wèn)題:Spring Schedule默認(rèn)使用服務(wù)器時(shí)區(qū),若需指定時(shí)區(qū),可在
@Scheduled注解中設(shè)置zone屬性,例如zone = "GMT+8"。 - 避免耗時(shí)操作:定時(shí)任務(wù)中應(yīng)避免執(zhí)行耗時(shí)過(guò)長(zhǎng)的操作,建議將耗時(shí)邏輯異步處理,或拆分任務(wù),防止阻塞調(diào)度線程。
到此這篇關(guān)于Java定時(shí)任務(wù)Schedule的基本用法及Cron表達(dá)式實(shí)踐的文章就介紹到這了,更多相關(guān)Java Schedule用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java覆蓋第三方j(luò)ar包中的某一個(gè)類的實(shí)現(xiàn)方法
在我們?nèi)粘5拈_發(fā)中,經(jīng)常需要使用第三方的 jar 包,有時(shí)候我們會(huì)發(fā)現(xiàn)第三方的 jar 包中的某一個(gè)類有問(wèn)題,或者我們需要定制化修改其中的邏輯,那么應(yīng)該如何實(shí)現(xiàn)呢,本文給大家介紹了Java覆蓋第三方j(luò)ar包中的某一個(gè)類的實(shí)現(xiàn)方法,需要的朋友可以參考下2025-02-02
SpringBoot實(shí)現(xiàn)過(guò)濾敏感詞的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用SpringBoot實(shí)現(xiàn)過(guò)濾敏感詞功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手嘗試一下2022-08-08
手寫java性能測(cè)試框架的實(shí)現(xiàn)示例
這篇文章主要為大家介紹了java實(shí)現(xiàn)性能測(cè)試框架示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
Java獲取客戶端真實(shí)IP地址經(jīng)典寫法詳解
在Web開發(fā)中,獲取客戶端的真實(shí)IP地址是一個(gè)常見需求,本文將分別給出經(jīng)典寫法(基于工具類/條件判斷)和Lambda寫法(基于函數(shù)式接口?+?流式處理)的實(shí)現(xiàn),并進(jìn)行對(duì)比2026-04-04
Java11中基于嵌套關(guān)系的訪問(wèn)控制優(yōu)化詳解
Java(和其他語(yǔ)言)通過(guò)內(nèi)部類支持嵌套類,要使其正常工作,需要編譯器執(zhí)行一些技巧,下面這篇文章主要給大家介紹了關(guān)于Java11中基于嵌套關(guān)系的訪問(wèn)控制優(yōu)化的相關(guān)資料,需要的朋友可以參考下2022-01-01
SpringBoot實(shí)現(xiàn)熱部署Community的示例代碼
本文主要介紹了SpringBoot實(shí)現(xiàn)熱部署Community的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Spring Boot Swagger2使用方法過(guò)程解析
這篇文章主要介紹了Spring Boot Swagger2使用方法過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08

