在日常項目運行中,我們總會有需求在某一時間段周期性的執行某個動作。比如每天在某個時間段導出報表,或者每隔多久統計一次現在線上的用戶量。在springboot中可以有很多方案去幫我們完成定時器的工作,有Java自帶的java.util.Timer類,也有強大的調度器Quartz,還有SpringBoo... ...
在日常項目運行中,我們總會有需求在某一時間段周期性的執行某個動作。比如每天在某個時間段導出報表,或者每隔多久統計一次現在線上的用戶量。在springboot中可以有很多方案去幫我們完成定時器的工作,有Java自帶的java.util.Timer類,也有強大的調度器Quartz,還有SpringBoot自帶的Scheduled,今天主要說說Scheduled。
v定時器比較
框架名稱 | Cron表達式 | 固定間隔執行 | 固定頻率執行 | 任務持久化 | 難易度 |
---|---|---|---|---|---|
TimerTask | 不支持 | 支持 | 支持 | 不支持 | 一般 |
schedule | 支持 | 支持 | 支持 | 不支持 | 簡單 |
Quartz | 支持 | 支持 | 支持 | 支持 | 難 |
在實際應用中,如果沒有分散式場景(quartz 支持分散式, schedule 不支持(需要自己實現,用分散式鎖),schedule跟spring結合的更好,還是很適用的。
v創建schedule工程
使用IntelliJ IDEA創建helloschedule
點擊finish完成項目的創建。
為了方便演示,使用@Slf4j輸出日誌,添加lombok引用,@Slf4j不清楚的可以看看SpringBoot(八)配置logback日誌
添加export類。
package com.task.log; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by toutou on 2018/10/20. */ @Component @Slf4j public class export { @Scheduled(cron = "0 0/1 * * * ?") public void minuteExport(){ log.debug("每分鐘執行一次的任務:" + getDate()); } @Scheduled(fixedRate = 5000) public void fiveSecondExport(){ log.debug("每5秒執行一次:" + getDate()); } @Scheduled(cron = "0/2 * * * * ?") public void twoSecondExport(){ log.debug("每2秒執行一次:" + getDate()); } @Scheduled(cron = "0 55 14 ? * *") public void regularTimeExport(){ log.debug("每天上午14點55分執行:" + getDate()); } private String getDate(){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(new Date()); } }
啟動類中添加@EnableScheduling
註解,然後運行。
查看IntelliJ IDEA控制台日誌和物理文件日誌
如上圖,簡單的定時任務輸出日誌搭建完成。
vcron詳細說明
cron表達式,有專門的語法,而且感覺有點繞人,不過簡單來說,大家記住一些常用的用法即可,特殊的語法可以單獨去查。
cron一共有7位,但是最後一位是年,可以留空,所以我們可以寫6位:
第一位,表示秒,取值0-59 第二位,表示分,取值0-59 第三位,表示小時,取值0-23 第四位,日期天/日,取值1-31 第五位,日期月份,取值1-12 第六位,星期,取值1-7,星期一,星期二...,註:不是第1周,第二周的意思 另外:1表示星期天,2表示星期一。 第七位,年份,可以留空,取值1970-2099cron中,還有一些特殊的符號,含義如下:
(*)星號:可以理解為每的意思,每秒,每分,每天,每月,每年... (?)問號:問號只能出現在日期和星期這兩個位置,表示這個位置的值不確定,每天3點執行,所以第六位星期的位置,我們是不需要關註的,就是不確定的值。同時:日期和星期是兩個相互排斥的元素,通過問號來表明不指定值。比如,1月10日,比如是星期1,如果在星期的位置是另指定星期二,就前後衝突矛盾了。 (-)減號:表達一個範圍,如在小時欄位中使用“10-12”,則表示從10到12點,即10,11,12 (,)逗號:表達一個列表值,如在星期欄位中使用“1,2,4”,則表示星期一,星期二,星期四 (/)斜杠:如:x/y,x是開始值,y是步長,比如在第一位(秒) 0/15就是,從0秒開始,每15秒,最後就是0,15,30,45,60 另:*/y,等同於0/y
附表:
"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" 2002年至2005年的每月的最後一個星期五上午10:15觸發
"0 15 10 ? * 6#3" 每月的第三個星期五上午10:15觸發
每隔5秒執行一次:*/5 * * * * ?
每隔1分鐘執行一次:0 */1 * * * ?
每天23點執行一次:0 0 23 * * ?
每天凌晨1點執行一次:0 0 1 * * ?
每月1號凌晨1點執行一次:0 0 1 1 * ?
每月最後一天23點執行一次:0 0 23 L * ?
每周星期天凌晨1點實行一次:0 0 1 ? * L
crontab 表達式線上生成https://tool.lu/crontab/
其他參考資料:
- Getting Started · Scheduling Tasks https://spring.io/guides/gs/scheduling-tasks/
- java - quartz相比於springboot schedule的優點? https://segmentfault.com/q/1010000012538852
- Spring Boot Quartz Scheduler Example: Building an Email Scheduling app | CalliCoderhttps://www.callicoder.com/spring-boot-quartz-scheduler-email-scheduling-example/
- SpringBoot之旅 -- 定時任務兩種(Spring Schedule 與 Quartz 整合 )實現 https://www.cnblogs.com/javanoob/p/springboot_schedule.html
作 者:請叫我頭頭哥
出 處:http://www.cnblogs.com/toutou/
關於作者:專註於基礎平臺的項目開發。如有問題或建議,請多多賜教!
版權聲明:本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
特此聲明:所有評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信我
聲援博主:如果您覺得文章對您有幫助,可以點擊文章右下角【推薦】一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!