1. 程式人生 > >Spring Boot入門(三):使用Scheduled註解實現定時任務

Spring Boot入門(三):使用Scheduled註解實現定時任務

發布 configure code tps enables err except rup .com

在程序開發的過程中,經常會使用到定時任務來實現一些功能,比如:

  • 系統依賴於外部系統的非核心數據,可以定時同步(每天同步一次)
  • 系統內部一些非核心數據的統計計算,可以定時計算(每天計算一次)

在Spring Boot中,我們可以使用@Scheduled註解來快速的實現定時任務。

@Scheduled註解主要支持以下3種方式:

  • fixedRate 固定頻率
  • fixedDelay 固定延遲
  • cron 自定義cron表達式

那麽接下來,我們講解下具體的實現方式。

1.fixedRate

首先,需要在啟動類上添加@EnableScheduling註解:

package com.zwwhnly.springbootdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class SpringbootdemoApplication {
    
    /*其他代碼*/
    
    public static void main(String[] args) {
        SpringApplication.run(SpringbootdemoApplication.class, args);
    }
}

然後,新建一個定時任務測試類TestSchedule,該類需要添加註解@Component,

最後,添加一個測試方法,該方法添加註解@Scheduled,為了能看到效果,我們每隔5秒輸出下系統的當前時間,如下所示:

package com.zwwhnly.springbootdemo;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class TestSchedule {
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // 每5秒執行一次
    @Scheduled(fixedRate = 5000)
    public void testFixedRate() {
        System.out.println("當前時間:" + simpleDateFormat.format(new Date()));
    }
}

啟動項目,我們會看到運行結果如下:

技術分享圖片

從運行結果來看,確實是每隔5秒輸出一次。

但是在實際項目中,不可能這麽規律,比如方法的執行時間超過了5秒呢(這個應該很常見),那麽彼時程序又是如何執行的呢?

我們先來修改下程序,讓方法的執行時間超過5秒:

// 每5秒執行一次
@Scheduled(fixedRate = 5000)
public void testFixedRate() {
    System.out.println("當前時間:" + simpleDateFormat.format(new Date()));
    try {
        Thread.sleep(6000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

此時的運行結果為:

技術分享圖片

從運行結果,我們可以看出,現在是每6秒輸出一次時間,由此我們可以得出結論:

如果方法的執行時間超過了定義的固定頻率(比如5秒),那麽上一次任務執行完成後,會立即執行下一次任務

2.fixedDelay

添加一個新方法testFixedDelay,這裏我們使用fixedDelay:

// 上次任務執行結束時間與下次任務執行開始的間隔時間為5s
@Scheduled(fixedDelay = 5000)
public void testFixedDelay()
{
   System.out.println("當前時間:" + simpleDateFormat.format(new Date()));
}

啟動項目,我們會看到運行結果如下:

當前時間:2019-04-09 10:28:56
當前時間:2019-04-09 10:29:01
當前時間:2019-04-09 10:29:06
當前時間:2019-04-09 10:29:11
當前時間:2019-04-09 10:29:16
當前時間:2019-04-09 10:29:21
當前時間:2019-04-09 10:29:26
當前時間:2019-04-09 10:29:31
當前時間:2019-04-09 10:29:36
當前時間:2019-04-09 10:29:41
當前時間:2019-04-09 10:29:46
當前時間:2019-04-09 10:29:51
當前時間:2019-04-09 10:29:56
當前時間:2019-04-09 10:30:01

看到運行結果,也許你會很疑惑,這不是和fixedRate的運行結果一樣嘛,也是每隔5秒執行一次。

其實不然,否則Spring Boot怎麽會同時支持fixedRate和fixedDelay呢,功能一樣,還容易混淆。

3.fixedRate與fixedDelay的區別

為了讓你更清晰的看到fixedRate與fixedDelay的區別,我們修改下fixedDelay方法,仍然是讓它的執行時間超過5秒:

// 上次任務執行結束時間與下次任務執行開始的間隔時間為5s
@Scheduled(fixedDelay = 5000)
public void testFixedDelay() {
    System.out.println("當前時間:" + simpleDateFormat.format(new Date()));
    try {
        Thread.sleep(6000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

此時的運行結果為:

當前時間:2019-04-09 10:36:04
當前時間:2019-04-09 10:36:15
當前時間:2019-04-09 10:36:26
當前時間:2019-04-09 10:36:37
當前時間:2019-04-09 10:36:48
當前時間:2019-04-09 10:36:59
當前時間:2019-04-09 10:37:10
當前時間:2019-04-09 10:37:21
當前時間:2019-04-09 10:37:32
當前時間:2019-04-09 10:37:43
當前時間:2019-04-09 10:37:54
當前時間:2019-04-09 10:38:05

我們可以看出,現在兩次輸出時間的間隔為11秒,由此我們可以得出結論:

使用fixedDelay,上一次任務執行完成後,會延遲5秒,再執行下一次任務

看到這裏,是不是明白了fixedRate與fixedDelay的區別呢,通俗講就是:

fixedRate是固定頻率執行,fixedDelay是延遲固定時間執行

4.cron

相比於上面講的兩種方式,cron表達式顯得更加靈活,因為它基本滿足各種場景的配置需求,比如固定頻率執行,固定某個時間點執行等。

首先,我們使用cron表達式實現上述例子中的每隔5秒執行一次:

@Scheduled(cron = "0/5 * * * * ?")
public void testCron() {
    System.out.println("當前時間:" + simpleDateFormat.format(new Date()));
}

運行結果為:

當前時間:2019-04-09 11:00:50
當前時間:2019-04-09 11:00:55
當前時間:2019-04-09 11:01:00
當前時間:2019-04-09 11:01:05
當前時間:2019-04-09 11:01:10
當前時間:2019-04-09 11:01:15
當前時間:2019-04-09 11:01:20
當前時間:2019-04-09 11:01:25
當前時間:2019-04-09 11:01:30

手動設置方法的執行時間超過5秒:

@Scheduled(cron = "0/5 * * * * ?")
public void testCron() {
    System.out.println("當前時間:" + simpleDateFormat.format(new Date()));
    try {
        Thread.sleep(6000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

此時的運行結果為:

當前時間:2019-04-09 11:16:15
當前時間:2019-04-09 11:16:25
當前時間:2019-04-09 11:16:35
當前時間:2019-04-09 11:16:45
當前時間:2019-04-09 11:16:55
當前時間:2019-04-09 11:17:05
當前時間:2019-04-09 11:17:15
當前時間:2019-04-09 11:17:25
當前時間:2019-04-09 11:17:35

如果想要設置成每天的某個時間點執行,比如我的個人博客http://www.zwwhnly.com/就是每晚20:00定時拉取GitHub代碼並使用Jekyll編譯到Nginx的目錄下實現的自動發布。

實現這個配置的cron表達式為:0 0 20 * * ? 。

更多的cron表達式,可以到http://cron.qqe2.com/去自定義,勾選好會自動生成cron表達式,非常方便。

5.源碼地址

https://github.com/zwwhnly/springbootdemo.git,歡迎大家下載,有問題可以多多交流。

6.參考鏈接

Springboot 之 使用Scheduled做定時任務

springboot使用@Scheduled做定時任務,以及連接池問題

Spring Boot入門(三):使用Scheduled註解實現定時任務