定時任務作爲系統調度工具,在某些系統中的特定場合有着廣泛應用,例如:在某個時間點統計數據、在一定的時間間隔取得最新數據等。Java開發中,以前我們實現定時任務時,最初使用Timer、TimerTask,Timer是定時器類,用來按計劃開啓後臺線程執行指定任務,TimerTask一個抽象類,它的子類代表一個可以被Timer計劃的任務。還可以用第三方Quartz,Quartz是一個優秀的定時任務框架,發展至今已經非常成熟,以致後來其他的定時任務框架的核心思想或底層大多源於Quartz。Springboot2框架本身通過@Scheduled
註解集成了定時任務,對於項目中簡單的調度方案是足夠支撐,可以直接使用,不用考慮其他模塊。
8.1 創建定時任務的項目
使用 @Scheduled 非常容易,直接創建一個 Spring Boot 項目,並且添加 web 依賴 spring-boot-starter-web
,項目創建成功後,添加 @EnableScheduling
註解,開啓定時任務。
package com.gavinbj.task;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* @SpringBootApplication 標註這是SpringBoot項目的主程序類
*/
@SpringBootApplication
@EnableScheduling
public class TaskApplication {
public static void main(String[] args) {
SpringApplication.run(TaskApplication.class, args);
}
}
8.2 創建定時任務類
package com.gavinbj.task.csdn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class WeatherReadTask {
private final static Logger logger = LoggerFactory.getLogger(WeatherReadTask.class);
// 每天8:00到23:00 每一分鐘執行一次
@Scheduled(cron = "0 0/1 8-23 * * *")
public void startReadWeather() {
logger.info("讀取天氣數據開始");
logger.info("讀取天氣數據結束");
}
// 第一次執行 延後10秒鐘;後續每隔50秒執行一次
@Scheduled(fixedRate = 50000, initialDelay = 10000)
public void startReadWechats() {
logger.info("讀取公衆號數據開始");
logger.info("讀取公衆號數據結束");
}
}
執行後輸出結果:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.1.RELEASE)
2020-01-30 16:07:16.279 INFO 17264 --- [ main] com.gavinbj.task.TaskApplication : Starting TaskApplication on 20190823-032019 with PID 17264 (C:\StsEclipse4.3.2\workspace\gavinbj-mp\gavinbj-task\target\classes started by Administrator in C:\StsEclipse4.3.2\workspace\gavinbj-mp\gavinbj-task)
2020-01-30 16:07:16.283 INFO 17264 --- [ main] com.gavinbj.task.TaskApplication : No active profile set, falling back to default profiles: default
2020-01-30 16:07:17.329 INFO 17264 --- [ main] o.a.coyote.http11.Http11NioProtocol : Initializing ProtocolHandler ["http-nio-9006"]
2020-01-30 16:07:17.330 INFO 17264 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-01-30 16:07:17.330 INFO 17264 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.27]
2020-01-30 16:07:17.403 INFO 17264 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/gavin] : Initializing Spring embedded WebApplicationContext
2020-01-30 16:07:17.736 INFO 17264 --- [ main] o.a.coyote.http11.Http11NioProtocol : Starting ProtocolHandler ["http-nio-9006"]
2020-01-30 16:07:17.758 INFO 17264 --- [ main] com.gavinbj.task.TaskApplication : Started TaskApplication in 2.618 seconds (JVM running for 2.948)
2020-01-30 16:07:27.740 INFO 17264 --- [ scheduling-1] com.gavinbj.task.csdn.WeatherReadTask : 讀取公衆號數據開始
2020-01-30 16:07:27.741 INFO 17264 --- [ scheduling-1] com.gavinbj.task.csdn.WeatherReadTask : 讀取公衆號數據結束
2020-01-30 16:08:00.094 INFO 17264 --- [ task-1] com.gavinbj.task.csdn.WeatherReadTask : 讀取天氣數據開始
2020-01-30 16:08:00.094 INFO 17264 --- [ task-1] com.gavinbj.task.csdn.WeatherReadTask : 讀取天氣數據結束
8.3 @Scheduled設置說明
關於@Scheduled
註解使用的三種方式:
8.3.1 fixedRate格式
fixedRate是按照一定的速率執行,是從上一次方法執行開始的時間算起,如果上一次方法阻塞住了,下一次也是不會執行,但是在阻塞這段時間內累計應該執行的次數,當不再阻塞時,一下子把這些全部執行掉,而後再按照固定速率繼續執行。有時搭配initialDelay使用,表示第一次延遲多長時間後執行,之後按fixedRate的規則每隔一定時間執行一次。
8.3.2 fixedDelay格式
fixedDelay控制方法執行的間隔時間,是以上一次方法執行完開始算起,如上一次方法執行阻塞住了,那麼直到上一次執行完,並間隔給定的時間後,執行下一次。
8.3.1 cron格式
- cron表達式格式
{秒} {分} {時} {日} {月} {周} {年(可選)}
- cron 表達式字段取值範圍及說明
字段 | 取值範圍 | 允許的特殊字符 |
---|---|---|
秒 | 0 ~ 59 | , - * / |
分 | 0 ~ 59 | , - * / |
時 | 0 ~ 23 | , - * / |
日 | 可以用數字 1 ~ 31 中的任意一個值,但要注意特殊月份 | , - * ? / L W C |
月 | 可以用 0 ~ 11 | , - * / |
周 | 可以用數字 1 ~ 7 表示(1=星期日) | , - * ? / L C # |
年 | 取值範圍(1970-2099),允許爲空值 | , - * / |
- cron表達式中特殊字符的說明
特殊字符 | 說明 |
---|---|
* | 表示可以匹配該域的所有值 |
? | 主要用於日和星期,可以匹配域的任意值,但實際不會。當2個子表達式其中之一被指定了值以後,爲了避免衝突,需要將另一個子表達式的值設爲? |
/ | 表示爲每隔一段時間。如 0 0/10 * * * ? 其中的 0/10表示從0分鐘開始,每隔10分鐘執行一次 |
- | 表示範圍。如 0 0-5 14 * * ? 表示在每天14:00到14:05期間每1分鐘執行一次 |
, | 表示枚舉多個值,這些值之間是"或"的關係。如 0 10,30 14 * 3 ? 表示每個星期二14點10分或者14點30分執行一次 |
L | 表示每月或者每週的最後一天。如 0 0 0 L * ? * 表示每月的最後一天執行 |
W | 表示最近工作日。如 0 0 0 15W * ?* 表示每月15號最近的那個工作日執行 |
# | 用來指定具體的週數,"#“前面代表星期,”#"後面代表本月的第幾周。如"2#1"表示本月第二週的星期日 |