回覆列表
-
1 # Java從入門到架構師
-
2 # 大劉哥聊技術
定時任務在實戰中是經常用到的一些功能。比如說定期發郵件,定期去檢查某項任務等等。對於定時呼叫的實現在實際開發之中可以使用:TimerTask,Quartz,SpringTask配置。接下來,我主要給大家講講使用springboot自帶的一個定時功能以及springboot整合Quartz。
一、SpringBoot自帶的一個定時功能SpringBoot自帶的一個定時功能,開箱即可使用。
不過需要先引入以下的依賴
第一步,我們可以在main方法加一個@EnableScheduling即可使用SpringBoot自帶的定時任務處理工具。
第二步,我們新建一個定時任務測試類ScheduledTest,並在類中新增定時任務的測試方法。
第三步:執行,檢視效果。
說明,定時任務啟動成功!非常的方便。不用我們去處理很複雜的配置。
二、Springboot整合Quartz整合第三方的定時框架Quartz,可以很方便的使用第三方提供的優秀功能。
第一步,新增一個定時任務類SampleJob,並且繼承QuartzJobBean。把我們需要執行的任務寫到executeInternal方法裡面。我這裡只寫了一個簡單的方法,列印一下字串。如下圖:
第二步,我們在main方法裡面新增一些測試的方法。
第三步:啟動SpringBoot應用,檢視效果。
在本文中,您將學習如何使用@Scheduled註釋在Spring Boot中安排任務。您還將學習如何使用自定義執行緒池執行所有計劃的任務。
該@Scheduled註釋被新增到一個方法有關何時執行它的一些資訊一起,和Spring引導負責剩下的照顧。
Spring Boot在內部使用TaskScheduler介面來排程帶註釋的方法以供執行。
本文的目的是構建一個簡單的專案,演示與任務計劃有關的所有概念。
建立專案
讓我們使用Spring Boot CLI建立專案。啟動您的終端並鍵入以下命令以生成專案-
$ spring init --name=scheduler-demo scheduler-demo
或者,您可以使用Spring Initializer Web應用程式生成專案。只需轉到http://start.spring.io/,輸入工件的值作為“ scheduler-demo”,然後單擊“ 生成”以生成並下載專案。
生成專案後,將其匯入您喜歡的IDE中。專案的目錄結構應如下所示-
啟用排程
您可以簡單地透過將@EnableScheduling註釋新增到主應用程式類或Configuration類之一來啟用排程。
像這樣開啟SchedulerDemoApplication.java並新增@EnableScheduling註釋-
package com.example.schedulerdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class SchedulerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerDemoApplication.class, args);
}
}
計劃任務
使用Spring Boot排程任務就像用註釋對方法進行@Scheduled註釋一樣簡單,並且提供很少的引數來決定任務執行的時間。
在新增任務之前,讓我們首先為所有計劃任務建立容器。使用以下內容建立一個名為ScheduledTasksinside com.example.schedulerdemopackage 的新類-
package com.example.schedulerdemo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
@Component
public class ScheduledTasks {
private static final Logger logger = LoggerFactory.getLogger(ScheduledTasks.class);
private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
public void scheduleTaskWithFixedRate() {}
public void scheduleTaskWithFixedDelay() {}
public void scheduleTaskWithInitialDelay() {}
public void scheduleTaskWithCronExpression() {}
}
該類包含四個空方法。我們將一一探討所有方法的實現。
所有計劃的方法都應遵循以下兩個條件-
該方法應具有void返回型別。
該方法不應接受任何引數。
涼!現在讓我們進入實現。
1.以固定速率計劃任務
您可以透過使用批註中的fixedRate引數來安排以固定間隔執行的方法@Scheduled。在下面的示例中,帶註釋的方法將每2秒執行一次。
@Scheduled(fixedRate = 2000)
public void scheduleTaskWithFixedRate() {
logger.info("Fixed Rate Task :: Execution Time - {}", dateTimeFormatter.format(LocalDateTime.now()) );
}
# Sample Output
Fixed Rate Task :: Execution Time - 10:26:58
Fixed Rate Task :: Execution Time - 10:27:00
Fixed Rate Task :: Execution Time - 10:27:02
....
....
該fixedRate任務在任務就算以前呼叫沒有完成指定的時間間隔呼叫。
2.安排固定延遲的任務
您可以使用fixedDelay引數在上一次呼叫完成與下一次呼叫開始之間以固定的延遲執行任務。
該fixedDelay引數計算上一次呼叫完成後的延遲。
考慮以下示例-
@Scheduled(fixedDelay = 2000)
public void scheduleTaskWithFixedDelay() {
logger.info("Fixed Delay Task :: Execution Time - {}", dateTimeFormatter.format(LocalDateTime.now()));
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException ex) {
logger.error("Ran into an error {}", ex);
throw new IllegalStateException(ex);
}
}
由於任務本身需要5秒鐘才能完成,並且我們已指定在上一次呼叫完成與下一次呼叫開始之間有2秒的延遲,因此每次呼叫之間會有7秒的延遲-
# Sample Output
Fixed Delay Task :: Execution Time - 10:30:01
Fixed Delay Task :: Execution Time - 10:30:08
Fixed Delay Task :: Execution Time - 10:30:15
....
....
3.安排具有固定速率和初始延遲的任務
您可以將initialDelay引數與fixedRate和fixedDelay一起使用,以指定的毫秒數延遲第一次執行任務。
在以下示例中,任務的首次執行將延遲5秒,然後將以2秒的固定間隔正常執行-
@Scheduled(fixedRate = 2000, initialDelay = 5000)
public void scheduleTaskWithInitialDelay() {
logger.info("Fixed Rate Task with Initial Delay :: Execution Time - {}", dateTimeFormatter.format(LocalDateTime.now()));
}
# Sample output (Server Started at 10:48:46)
Fixed Rate Task with Initial Delay :: Execution Time - 10:48:51
Fixed Rate Task with Initial Delay :: Execution Time - 10:48:53
Fixed Rate Task with Initial Delay :: Execution Time - 10:48:55
....
....
4.使用Cron表示式安排任務
如果上述簡單引數不能滿足您的需求,則可以使用cron表示式來計劃任務的執行。
在以下示例中,我已安排了每分鐘執行一次的任務-
@Scheduled(cron = "0 * * * * ?")
public void scheduleTaskWithCronExpression() {
logger.info("Cron Task :: Execution Time - {}", dateTimeFormatter.format(LocalDateTime.now()));
}
# Sample Output
Cron Task :: Execution Time - 11:03:00
Cron Task :: Execution Time - 11:04:00
Cron Task :: Execution Time - 11:05:00
在自定義執行緒池中執行@Scheduled任務
預設情況下,所有@Scheduled任務都在Spring建立的大小為1的預設執行緒池中執行。
您可以透過在所有方法中記錄當前執行緒的名稱來進行驗證-
logger.info("Current Thread : {}", Thread.currentThread().getName());
所有方法將列印以下內容-
Current Thread : pool-1-thread-1
但是,您可以建立自己的執行緒池,並將Spring配置為使用該執行緒池執行所有計劃的任務。
config在內部建立一個新包com.example.schedulerdemo,然後使用以下內容建立一個名為SchedulerConfig內部config包的新類-
package com.example.schedulerdemo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
private final int POOL_SIZE = 10;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
threadPoolTaskScheduler.setThreadNamePrefix("my-scheduled-task-pool-");
threadPoolTaskScheduler.initialize();
scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
這就是將Spring配置為使用自己的執行緒池而不是預設執行緒池所需要做的全部工作。
如果您現在以預定的方法記錄當前執行緒的名稱,則將得到如下輸出:
Current Thread : my-scheduled-task-pool-1
Current Thread : my-scheduled-task-pool-2
# etc...
結論
在本文中,您學習瞭如何使用@Scheduled批註在Spring Boot中計劃任務。您還學習瞭如何使用自定義執行緒池來執行這些任務。