@
一、前言介紹
定時任務是企業開發中很常用的,比如定時推送一些接口數據,在java中實現定時任務的方法有Spring Task、Quartz等等框架,也有JDK自帶的ScheduledExecutorService、Timer
Quartz框架比較復雜,之前我寫過一個入門教程,讀者可以參考學習:Quartz系列之任務調度框架原理簡介
Spring Task是Spring3.0以后自帶的task,可以將它看成一個輕量級的Quartz,而且使用起來比Quartz簡單許多
二、Spring Task
2.1 SpringTask簡介
Spring Task不是獨立的項目,是spring-context 模塊下提供的定時任務工具,是Spring3.0以后自帶的task,可以將它看成一個輕量級的Quartz
2.2 實驗環境准備
- JDK 1.8
- SpringBoot2.2.1
- Maven 3.2+
- 開發工具
- IntelliJ IDEA
- smartGit
創建一個SpringBoot Initialize項目,詳情可以參考我之前博客:SpringBoot系列之快速創建項目教程
SpringBoot項目引入spring-boot-starter-web既可,因為wen場景啟動器會自動引入spring-context依賴:
pom.xml參考
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.springboot</groupId>
<artifactId>springboot-scheduler-task</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-scheduler-task</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.3 Enable Scheduling
開啟Spring Scheduling必須使用@EnableScheduling注解,可以新建一個配置類,然后加上注解
package com.example.springboot.scheduler.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* <pre>
* TaskSchedulerConfiguration
* </pre>
*
* <pre>
* @author mazq
* 修改記錄
* 修改后版本: 修改人: 修改日期: 2020/07/20 13:57 修改內容:
* </pre>
*/
@Configuration
@EnableScheduling
public class TaskSchedulerConfiguration {
}
也可以像官網例子一樣,加在application類:
2.4 單線程定時任務
Spring Task使用定時任務,只要加上@Scheduled注解,然后也要加到Spring容器中,使用可以加上@Service等注解就可以,Scheduled策略:cron 、fixedDelay、fixedRate 三選一
ok,下面介紹@Scheduled的4個關鍵屬性
- fixedDelay
Spring官網找到API文檔:
意思是:在上一次調用的結束與下一次調用的開始之間以固定的毫秒數為單位執行帶注釋的方法。
ps:這種策略比較好理解,意思就是不管任務執行時間,只關注時間間隔就可以,畫圖表示:
- fixedRate
意思是: 兩次調用之間以固定的時間段(以毫秒為單位)執行帶注釋的方法。
這種策略先預計任務執行時間,fixedRate參數指定,畫圖描述,如圖,fixedRate=10000(10s):
代碼例子:每個任務計划執行5s
@Scheduled( fixedRate = 5000)
public void testFixedRate() {
log.info("fixedRate test,thread name:[{}],execute time:[{}]",Thread.currentThread().getName(),
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
- cron
cron參數是用cron表達式的意思,cron表達式含義:
Cron表達式是一個字符串,字符串以5或6個空格隔開,分為6或7個域,每一個域代表一個含義。
用表格表示Cron表達式:
位置 | 時間域 | 允許值 | 特殊值 |
---|---|---|---|
1 | 秒 | 0-59 | ,- * / |
2 | 分鍾 | 0-59 | ,- * / |
3 | 小時 | 0-23 | ,- * / |
4 | 日期 | 1-31 | ,- * ? / L W C |
5 | 月份 | 1-12 | ,- * / |
6 | 星期 | 1-7 | ,- * ? / L C # |
7 | 年份(可選) | 1-31 | ,- * / |
特殊字符 | 代表含義 |
---|---|
, | 枚舉,表達一個列表值,如在星期字段中使用“MON,WED,FRI”,則表示星期一,星期三和星期五; |
- | 區間 ,表達一個范圍,如在小時字段中使用“10-12”,則表示從10到12點,即10,11,12; |
* | 任意,可用在所有字段中,表示對應時間域的每一個時刻,例如, 在分鍾字段時,表示“每分鍾”; |
/ | 步長,x/y表達一個等步長序列,x為起始值,y為增量步長值。如在分鍾字段中使用0/15,則表示為0,15,30和45秒,而5/15在分鍾字段中表示5,20,35,50,你也可以使用*/y,它等同於0/y; |
? | 該字符只在日期和星期字段中使用,它通常指定為“無意義的值”,相當於點位符; |
L | 該字符只在日期和星期字段中使用,代表“Last”的意思,但它在兩個字段中意思不同。L在日期字段中,表示這個月份的最后一天,如一月的31號,非閏年二月的28號;如果L用在星期中,則表示星期六,等同於7。但是,如果L出現在星期字段里,而且在前面有一個數值X,則表示“這個月的最后X天”,例如,6L表示該月的最后星期五; |
W | 工作日,該字符只能出現在日期字段里,是對前導日期的修飾,表示離該日期最近的工作日。例如15W表示離該月15號最近的工作日,如果該月15號是星期六,則匹配14號星期五;如果15日是星期日,則匹配16號星期一;如果15號是星期二,那結果就是15號星期二。但必須注意關聯的匹配日期不能夠跨月,如你指定1W,如果1號是星期六,結果匹配的是3號星期一,而非上個月最后的那天。W字符串只能指定單一日期,而不能指定日期范圍; |
C | 該字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是計划所關聯的日期,如果日期沒有被關聯,則相當於日歷中所有日期。例如5C在日期字段中就相當於日歷5日以后的第一天。1C在星期字段中相當於星期日后的第一天。 |
# | 該字符只能在星期字段中使用,表示當月某個工作日。如6#3表示當月的第三個星期五(6表示星期五,#3表示當前的第三個),而4#5表示當月的第五個星期三,假設當月沒有第五個星期三,忽略不觸發; |
LW | LW組合,在日期字段可以組合使用LW,它的意思是當月的最后一個工作日; |
每隔1分鍾執行一次:
@Scheduled(cron = "0 0/1 * * * ? ")
public void testCron(){
log.info("cron test,thread name:[{}],execute time:[{}]",Thread.currentThread().getName(),
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
- initialDelay
initialDelay 初始化延遲時間,也就是標識第一次延遲執行的時間,只能配合 fixedDelay 或 fixedRate 使用
@Scheduled(initialDelay = 5000, fixedRate = 5000)
public void testFixedRate() {
log.info("fixedRate test,thread name:[{}],execute time:[{}]",Thread.currentThread().getName(),
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
2.5 線程池的使用配置
配置文件加上代碼,配置線程池
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(5);
threadPoolTaskScheduler.setThreadNamePrefix("ThreadPoolTaskScheduler");
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
return threadPoolTaskScheduler;
}
也可以在application配置文件,加上:
ps:當然,不做配置也是可以的,因為SpringBoot有做自動配置,自己不改配置的,就全部按照SpringBoot的自動配置(默認)
代碼例子下載:code download