前言
在開發中,我們會有定時執行某些任務的需求,例如定時清理過期文件、定時發送郵件等等。SpringBoot 爲我們提供了便捷的方式來配置定時任務,只需要打上幾個註解即可。那麼下面讓我們來看看 SpringBoot 中如何開發定時任務。
開啓定時任務
想要使用定時任務,需先打開定時任務開關。
在入口類中添加 @EnableScheduling
註解
@SpringBootApplication
@EnableScheduling
public class SchedulerTaskApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerTaskApplication.class, args);
}
}
使用 @Scheduled 配置定時任務
配置定時任務非常簡單,只需要在需要定時執行的方法上添加 @Scheduled
註解即可。注意,該類上需要打上組件型註解,例如 @Componet
,這樣該類纔會被注入到 Spring 容器中進行管理,@Scheduled
纔會生效。例如:
@Component
public class SchedulerTask1 {
private static final Logger LOG = LoggerFactory.getLogger(SchedulerTask1.class);
/**
* 每秒執行一次
*/
@Scheduled(cron = "* * * * * ?")
public void scheduler1() {
LOG.info("scheduler1 測試: " + System.currentTimeMillis());
}
}
運行程序,結果如下:
2020-06-19 00:28:06.002 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 測試: 1592497686002
2020-06-19 00:28:07.003 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 測試: 1592497687003
2020-06-19 00:28:08.002 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 測試: 1592497688002
2020-06-19 00:28:09.002 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 測試: 1592497689002
2020-06-19 00:28:10.001 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 測試: 1592497690001
2020-06-19 00:28:11.001 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 測試: 1592497691001
2020-06-19 00:28:12.005 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 測試: 1592497692005
2020-06-19 00:28:13.001 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 測試: 1592497693001
可以看到,日誌每秒鐘打印一次,這說明該方法每秒鐘被執行一次。
@Scheduled 註解參數說明
@Scheduled
支持多種定時規則進行配置。
- cron:
cron
表達式是 Linux 中定時任務的配置規則。具體使用方式可以參考 cron。文末也附上了一些配置示例,方便大家參考。 - zone: 時區。默認爲服務器所在時區,接收類型爲
java.util.TimeZone
。 - fixedDelay / fixedDelayString: 表示在上次執行之後多久後再次執行。它倆的區別爲前者類型爲
long
類型,後者爲String
,單位均爲 ms。 - fixedRate / fixedRateString: 表示在上次執行開始之後多久後再次執行。同樣,它倆的區別也僅爲參數類型的區別。
- initialDelay / initialDelayString: 表示第一次任務執行延遲多久,區別同上。
@Scheduled 的多線程使用
@Scheduled
默認是單線程執行的,多個 @Scheduled
任務都用的同一個線程。如果某個任務是個耗時的操作,那麼其它定時任務都會因爲這一個耗時的任務而堵塞。
例如,兩個定時任務 A、B 都是每秒觸發一次。如果任務 A 執行一次需要耗時 5 秒,則任務 A、B 都要等任務 A 執行後才能再執行,這就達不到任務 A、B 每秒執行一次的效果了。
那麼,如何能讓每個定時任務按照配置好的定時規則準時執行呢?這就需要我們將定時任務配置成多線程的方式。
在入口類中添加 @EnableAsync
,開啓異步執行。在定時任務上添加 @Async
註解,標識該方法異步執行。方法中我們通過 sleep
來模擬耗時操作。
@Component
public class SchedulerTask2 {
private static final Logger LOG = LoggerFactory.getLogger(SchedulerTask2.class);
/**
* 每秒執行一次
*/
@Async
@Scheduled(cron = "* * * * * ?")
public void scheduler1() {
LOG.info("SchedulerTask2 scheduler1 執行: " + System.currentTimeMillis());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LOG.info("SchedulerTask2 scheduler1 執行完了: " + System.currentTimeMillis());
}
}
運行程序我們可以看到:
2020-06-19 01:13:04.011 INFO 13495 --- [ task-1] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行: 1592500384011
2020-06-19 01:13:05.002 INFO 13495 --- [ task-2] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行: 1592500385002
2020-06-19 01:13:06.002 INFO 13495 --- [ task-3] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行: 1592500386001
2020-06-19 01:13:07.005 INFO 13495 --- [ task-4] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行: 1592500387004
2020-06-19 01:13:08.003 INFO 13495 --- [ task-5] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行: 1592500388003
2020-06-19 01:13:09.003 INFO 13495 --- [ task-6] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行: 1592500389003
2020-06-19 01:13:09.013 INFO 13495 --- [ task-1] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行完了: 1592500389013
2020-06-19 01:13:10.004 INFO 13495 --- [ task-2] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行完了: 1592500390004
2020-06-19 01:13:10.004 INFO 13495 --- [ task-7] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行: 1592500390004
2020-06-19 01:13:11.002 INFO 13495 --- [ task-3] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行完了: 1592500391002
2020-06-19 01:13:11.003 INFO 13495 --- [ task-8] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 執行: 1592500391003
雖然方法執行需要耗時 5 秒,但是每個任務還是按照每秒鐘觸發一次準時執行了。通過前面的 task-n 可以看出,每個任務的執行都使用了不同的線程。
@Async
默認線程池個數爲 8 個,我們也可以通過配置來滿足不同場景的需要。有關 @Async
多線程的使用,我會在後續的章節爲大家介紹。
以上就是 SpringBoot 定時任務的使用方法。
附1:Cron 表達式示例
0 0 2 1 * ? * 表示在每月的1日的凌晨2點調度任務
0 15 10 ? * MON-FRI 表示週一到週五每天上午10:15執行作業
0 15 10 ? * 6L 2002-2006 表示2002-2006年的每個月的最後一個星期五上午10:15執行作
0 0 10,14,16 * * ? 每天上午10點,下午2點,4點
0 0/30 9-17 * * ? 朝九晚五工作時間內每半小時
0 0 12 ? * WED 表示每個星期三中午12點
0 0 12 * * ? 每天中午12點觸發
0 15 10 ? * * 每天上午10:15觸發
0 15 10 * * ? 每天上午10:15觸發
0 15 10 * * ? * 每天上午10:15觸發
0 15 10 * * ? 2005 2005年的每天上午10:15觸發
0 * 14 * * ? 在每天下午2點到下午2:59期間的每1分鐘觸發
0 0/5 14 * * ? 在每天下午2點到下午2:55期間的每5分鐘觸發
0 0/5 14,18 * * ? 在每天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發
0 0-5 14 * * ? 在每天下午2點到下午2:05期間的每1分鐘觸發
0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44觸發
0 15 10 ? * MON-FRI 週一至週五的上午10:15觸發
0 15 10 15 * ? 每月15日上午10:15觸發
0 15 10 L * ? 每月最後一日的上午10:15觸發
0 15 10 ? * 6L 每月的最後一個星期五上午10:15觸發
0 15 10 ? * 6L 2002-2005 002年至2005年的每月的最後一個星期五上午10:15觸發
0 15 10 ? * 6#3 每月的第三個星期五上午10:15觸發
本章代碼:GitHub
我是因特馬,一個愛分享的斜槓程序員~
歡迎關注我的公衆號:一隻因特馬
原文作者: 一隻因特馬
原文鏈接: https://www.interhorse.cn/a/1174570529/
版權聲明: 本博客所有文章除特別聲明外,均採用 BY-NC-ND 許可協議。轉載請註明出處!