一文讀懂SpringBoot定時任務

寫在前面: 從2018年底開始學習SpringBoot,也用SpringBoot寫過一些項目。這裏對學習Springboot的一些知識總結記錄一下。如果你也在學習SpringBoot,可以關注我,一起學習,一起進步。

相關文章:

【Springboot系列】Springboot入門到項目實戰


定時任務作用

定時任務顧名思義就是定時執行一個指定的方法。在項目中也很常用,比如:

  1. 定時向用戶發送短信、郵件等。
  2. 定期統計數據。
  3. 天氣預報系統定期更新數據。

SpringBoot中使用定時任務

1、創建定時器

使用SpringBoot項目中創建定時任務非常簡單,只需幾行代碼便可完成。新建一個Timer類作爲定期任務類。代碼如下:

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import java.text.SimpleDateFormat;
import java.util.Date;

@Configuration      //主要用於標記配置類,兼備Component的效果。
@EnableScheduling   //開啓定時任務
public class Timer {
    //添加定時任務,每隔5秒執行一次
    @Scheduled(cron = "0/5 * * * * ?")
    private void configureTasks() {
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("HH:mm:ss");
        System.out.println("當前時間:"+simpleDateFormat.format(new Date()));
    }
}

【注】 其中@Scheduled註解用於開啓定時任務,@Scheduled註解的核心屬性是cron,代表定時任務的觸發計劃表達式。這個表達式的格式爲:

seconds秒,minutes分鐘,hours小時,day天,month月,week星期,year年(可選添加)
@Scheduled(cron="seconds minutes hours day month week year")

2、運行效果

定時任務方法中輸出了當前時間,用於顯示定時任務效果。上面定時器方法設置的是每隔5秒執行一次,效果如下:
在這裏插入圖片描述

3、cron表達式

cron表達式中,每個位置的約束如下:

序號 說明 是否必填 通配符
1 0-59 , - * /
2 0-59 , - * /
3 小時 0-23 , - * /
4 1-31 , - * /
5 1-12 , - * / L W
6 星期 1-7/SUN-SAT , - * / ? L #
7 1970-2099 , - * /
  1. 星號( * ):可用在所有字段中,表示對應時間域的所有值,例如,* 在分鐘字段時,表示“每分鐘都會觸發”。
  2. 問號(?):該字符只在日期和星期字段中使用,它通常指定爲“無意義的值”,相當於佔位符。
  3. 減號(-):表達一個範圍,如在小時字段中使用“10-12”,則表示從10到12點,即10, 11, 12。
  4. 逗號(,):表達一個列表值,如在星期字段中使用“1, 2, 3”,則表示星期一,星期三和星期五。
  5. 斜槓(/):x / y表達一個等步長序列,x爲起始值,y爲增量步長值。如在秒數字段中使用0 / 15,則表示爲0, 15, 30和45秒,而5 / 15在分鐘字段中表示5, 20, 35, 50,你也可以使用* / y,它等同於0 / y。
  6. L:該字符只在日期和星期字段中使用,代表“Last”的意思,但它在兩個字段中意思不同。L在日期字段中,表示這個月份的最後一天,如一月的31號,非閏年二月的28號;如果L用在星期中,則表示星期六,等同於7。但是,如果L出現在星期字段裏,而且在前面有一個數值X,則表示“這個月的最後X天”,例如,6L表示該月的最後星期五。
  7. W:該字符只能出現在日期字段裏,是對前導日期的修飾,表示離該日期最近的工作日。例如15W表示離該月15號最近的工作日,如果該月15號是星期六,則匹配14號星期五;如果15日是星期日,則匹配16號星期一;如果15號是星期二,那結果就是15號星期二。但必須注意關聯的匹配日期不能夠跨月,如你指定1W,如果1號是星期六,結果匹配的是3號星期一,而非上個月最後的那天。W字符串只能指定單一日期,而不能指定日期範圍。
  8. LW組合:在日期字段可以組合使用LW,它的意思是當月的最後一個工作日。
  9. 井號(#):該字符只能在星期字段中使用,表示當月某個工作日。如6#3表示當月的第三個星期五(6表示星期五,#3表示當前的第三個),而4#5表示當月的第五個星期三,假設當月沒有第五個星期三,忽略不觸發。
  10. C:該字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是計劃所關聯的日期,如果日期沒有被關聯,則相當於日曆中所有日期。例如5C在日期字段中就相當於日曆5日以後的第一天。1C在星期字段中相當於星期日後的第一天。

Cron表達式參數值:

  1. 秒(0~59) 例如0/5表示每5秒
  2. 分(0~59)
  3. 時(0~23)
  4. 日(0~31)的某天,需計算
  5. 月(0~11)
  6. 星期( 可填1-7[1表示星期天,7表示星期六] 或 SUN/MON/TUE/WED/THU/FRI/SAT)

常用的cron表達式含義

每隔5秒執行一次:0/5 * * * * ? 
每隔1分鐘執行一次:0 */1 * * * ? 
每天24點執行一次:0 0 0 * * ? 
每月1號凌晨1點執行一次:0 0 1 1 * ?
每月最後一天24點執行一次:0 0 24 L * ? 
每週星期天凌晨1點實行一次:0 0 1 ? * L 
在15分、35分、40分執行一次:0 15,35,40 * * * ?
每天的0點、10點、15點、20點都執行一次:0 0 0,10,15,20 * * ?

4、fixedRate

fixedRate 兩次執行任務時間間隔是任務的開始點,也就是上一次執行開始多少毫秒後執行。

@Configuration      //主要用於標記配置類,兼備Component的效果。
@EnableScheduling   //開啓定時任務
@EnableAsync    //開啓多線程
public class Timer {
    @Scheduled(fixedRate  = 3000)
    @Async
    public void configureTasks() {
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("HH:mm:ss");
        System.out.println("開始,時間是 : "+simpleDateFormat.format(new Date())+""+Thread.currentThread().getName());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("結束,時間是 : "+simpleDateFormat.format(new Date())+""+Thread.currentThread().getName());
    }
}

【注】 fixedRate屬性值的單位爲毫秒,因爲使用到了線程,所以需要在類上添加上@EnableAsync 註解,開啓多線程。爲了能看出效果,在控制檯輸出時開始執行後,線程休眠5秒後在執行。
運行效果(是在上一次執行開始後3秒執行,輸出用線程的名字區分):
在這裏插入圖片描述
可以看出第一次執行,過了三秒,方法又開始執行了,此時第一次執行的方法還沒有結束。

5、fixedDelay

fixedDelay 的間隔是前次任務的結束與下次任務的開始,也就是上一次執行完成後多少毫秒後執行。

@Configuration      //主要用於標記配置類,兼備Component的效果。
@EnableScheduling   //開啓定時任務
@EnableAsync    //開啓多線程
public class Timer {
    @Scheduled(fixedDelay   = 3000)
    @Async
    public void configureTasks() {
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("HH:mm:ss");
        System.out.println("開始,時間是 : "+simpleDateFormat.format(new Date())+""+Thread.currentThread().getName());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("結束,時間是 : "+simpleDateFormat.format(new Date())+""+Thread.currentThread().getName());
    }
}

【注】 fixedDelay屬性值的單位爲毫秒,在控制檯輸出時開始執行後,線程休眠5秒後在執行。
運行效果(是在上一次執行開始後3秒執行,輸出用線程的名字區分):
在這裏插入圖片描述
可以看出第一次執行完成後又過了3秒後,纔開始重新執行。

最後有什麼不足之處,歡迎大家指出,期待與你的交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章