在程式開發的過程中,經常會使用到定時任務來實現一些功能,比如:
- 系統依賴於外部系統的非核心資料,可以定時同步(每天同步一次)
- 系統內部一些非核心資料的統計計算,可以定時計算(每天計算一次)
在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
如果想要設定成每天的某個時間點執行,比如我的個人部落格www.zwwhnly.com/就是每晚20:00定時拉取GitHub程式碼並使用Jekyll編譯到Nginx的目錄下實現的自動釋出。
實現這個配置的cron表示式為:0 0 20 * * ? 。
更多的cron表示式,可以到cron.qqe2.com/去自定義,勾選好會自動生成cron表示式,非常方便。
5.原始碼地址
github.com/zwwhnly/spr…,歡迎大家下載,有問題可以多多交流。