任務執行與排程
如果在上下文中沒有 Executor bean,Spring Boot 會自動配置一個 AsyncTaskExecutor。當啟用虛擬執行緒時(使用 Java 21+ 且 spring.threads.virtual.enabled 設定為 true),這將是一個使用虛擬執行緒的 SimpleAsyncTaskExecutor。否則,它將是一個帶有合理預設值的 ThreadPoolTaskExecutor。
除非定義了自定義的 Executor bean,否則自動配置的 AsyncTaskExecutor 將用於以下整合:
-
使用
@EnableAsync執行非同步任務,除非定義了AsyncConfigurer型別的 bean。 -
在 Spring for GraphQL 中非同步處理控制器方法返回的
Callable值。 -
Spring MVC 中的非同步請求處理。
-
Spring WebFlux 中的阻塞執行支援。
-
用於 Spring WebSocket 中的入站和出站訊息通道。
-
基於 JPA 倉庫引導模式的 JPA 引導執行器。
-
用於
ApplicationContext中 bean 的後臺初始化的引導執行器。
雖然這種方法在大多數情況下都有效,但 Spring Boot 允許您覆蓋自動配置的 AsyncTaskExecutor。預設情況下,當註冊了自定義的 Executor bean 時,自動配置的 AsyncTaskExecutor 會回退,而自定義的 Executor 將用於常規任務執行(透過 @EnableAsync)。
然而,Spring MVC、Spring WebFlux 和 Spring GraphQL 都需要一個名為 applicationTaskExecutor 的 bean。對於 Spring MVC 和 Spring WebFlux,此 bean 必須是 AsyncTaskExecutor 型別,而 Spring GraphQL 不強制執行此型別要求。
如果存在此型別的單個 bean 或定義了名為 applicationTaskExecutor 的 bean,Spring WebSocket 和 JPA 將使用 AsyncTaskExecutor。
最後,ApplicationContext 的引導執行器使用名為 applicationTaskExecutor 的 bean,除非定義了名為 bootstrapExecutor 的 bean。
以下程式碼片段演示瞭如何註冊自定義的 AsyncTaskExecutor 以與 Spring MVC、Spring WebFlux、Spring GraphQL、Spring WebSocket、JPA 以及 bean 的後臺初始化一起使用。
-
Java
-
Kotlin
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
@Configuration(proxyBeanMethods = false)
public class MyTaskExecutorConfiguration {
@Bean("applicationTaskExecutor")
SimpleAsyncTaskExecutor applicationTaskExecutor() {
return new SimpleAsyncTaskExecutor("app-");
}
}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.task.SimpleAsyncTaskExecutor
@Configuration(proxyBeanMethods = false)
class MyTaskExecutorConfiguration {
@Bean("applicationTaskExecutor")
fun applicationTaskExecutor(): SimpleAsyncTaskExecutor {
return SimpleAsyncTaskExecutor("app-")
}
}
|
如果應用程式上下文中沒有 |
|
如果既未定義自動配置的 |
如果您的應用程式需要多個 Executor bean 用於不同的整合,例如一個用於使用 @EnableAsync 的常規任務執行,另一個用於 Spring MVC、Spring WebFlux、Spring WebSocket 和 JPA,您可以按如下方式配置它們。
-
Java
-
Kotlin
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration(proxyBeanMethods = false)
public class MyTaskExecutorConfiguration {
@Bean("applicationTaskExecutor")
SimpleAsyncTaskExecutor applicationTaskExecutor() {
return new SimpleAsyncTaskExecutor("app-");
}
@Bean("taskExecutor")
ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("async-");
return threadPoolTaskExecutor;
}
}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.task.SimpleAsyncTaskExecutor
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
@Configuration(proxyBeanMethods = false)
class MyTaskExecutorConfiguration {
@Bean("applicationTaskExecutor")
fun applicationTaskExecutor(): SimpleAsyncTaskExecutor {
return SimpleAsyncTaskExecutor("app-")
}
@Bean("taskExecutor")
fun taskExecutor(): ThreadPoolTaskExecutor {
val threadPoolTaskExecutor = ThreadPoolTaskExecutor()
threadPoolTaskExecutor.setThreadNamePrefix("async-")
return threadPoolTaskExecutor
}
}
|
自動配置的
|
如果名為 taskExecutor 的 bean 不是一個選項,您可以將您的 bean 標記為 @Primary 或定義一個 AsyncConfigurer bean 來指定負責使用 @EnableAsync 處理常規任務執行的 Executor。以下示例演示瞭如何實現這一點。
-
Java
-
Kotlin
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
@Configuration(proxyBeanMethods = false)
public class MyTaskExecutorConfiguration {
@Bean
AsyncConfigurer asyncConfigurer(ExecutorService executorService) {
return new AsyncConfigurer() {
@Override
public Executor getAsyncExecutor() {
return executorService;
}
};
}
@Bean
ExecutorService executorService() {
return Executors.newCachedThreadPool();
}
}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.scheduling.annotation.AsyncConfigurer
import java.util.concurrent.Executor
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
@Configuration(proxyBeanMethods = false)
class MyTaskExecutorConfiguration {
@Bean
fun asyncConfigurer(executorService: ExecutorService): AsyncConfigurer {
return object : AsyncConfigurer {
override fun getAsyncExecutor(): Executor {
return executorService
}
}
}
@Bean
fun executorService(): ExecutorService {
return Executors.newCachedThreadPool()
}
}
要在保留自動配置的 AsyncTaskExecutor 的同時註冊自定義的 Executor,您可以建立一個自定義的 Executor bean,並在其 @Bean 註解中設定 defaultCandidate=false 屬性,如下例所示:
-
Java
-
Kotlin
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyTaskExecutorConfiguration {
@Bean(defaultCandidate = false)
@Qualifier("scheduledExecutorService")
ScheduledExecutorService scheduledExecutorService() {
return Executors.newSingleThreadScheduledExecutor();
}
}
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
@Configuration(proxyBeanMethods = false)
class MyTaskExecutorConfiguration {
@Bean(defaultCandidate = false)
@Qualifier("scheduledExecutorService")
fun scheduledExecutorService(): ScheduledExecutorService {
return Executors.newSingleThreadScheduledExecutor()
}
}
在這種情況下,您將能夠將自定義的 Executor 自動裝配到其他元件中,同時保留自動配置的 AsyncTaskExecutor。但是,請記住在 @Autowired 旁邊使用 @Qualifier 註解。
如果這對您來說不可能,您可以要求 Spring Boot 無論如何都自動配置一個 AsyncTaskExecutor,如下所示:
-
屬性
-
YAML
spring.task.execution.mode=force
spring:
task:
execution:
mode: force
自動配置的 AsyncTaskExecutor 將自動用於所有整合,即使註冊了自定義的 Executor bean,包括那些標記為 @Primary 的。這些整合包括:
-
非同步任務執行(
@EnableAsync),除非存在AsyncConfigurerbean。 -
Spring for GraphQL 非同步處理控制器方法返回的
Callable值。 -
Spring MVC 的非同步請求處理。
-
Spring WebFlux 的阻塞執行支援。
-
用於 Spring WebSocket 中的入站和出站訊息通道。
-
基於 JPA 倉庫引導模式的 JPA 引導執行器。
-
用於
ApplicationContext中 bean 的後臺初始化的引導執行器,除非定義了名為bootstrapExecutor的 bean。
|
根據您的目標安排,您可以將 |
|
當啟用 |
當自動配置 ThreadPoolTaskExecutor 時,執行緒池使用 8 個核心執行緒,這些執行緒可以根據負載增長和收縮。這些預設設定可以使用 spring.task.execution 名稱空間進行微調,如下例所示:
-
屬性
-
YAML
spring.task.execution.pool.max-size=16
spring.task.execution.pool.queue-capacity=100
spring.task.execution.pool.keep-alive=10s
spring:
task:
execution:
pool:
max-size: 16
queue-capacity: 100
keep-alive: "10s"
這會將執行緒池更改為使用有界佇列,因此當佇列滿(100 個任務)時,執行緒池會增加到最大 16 個執行緒。池的收縮更具侵略性,因為執行緒在空閒 10 秒後(而不是預設的 60 秒)就會被回收。
如果排程器需要與計劃任務執行關聯(例如使用 @EnableScheduling),也可以自動配置排程器。
如果啟用虛擬執行緒(使用 Java 21+ 且 spring.threads.virtual.enabled 設定為 true),這將是一個使用虛擬執行緒的 SimpleAsyncTaskScheduler。此 SimpleAsyncTaskScheduler 將忽略任何與池相關的屬性。
如果未啟用虛擬執行緒,它將是一個帶有合理預設值的 ThreadPoolTaskScheduler。ThreadPoolTaskScheduler 預設使用一個執行緒,其設定可以使用 spring.task.scheduling 名稱空間進行微調,如下例所示:
-
屬性
-
YAML
spring.task.scheduling.thread-name-prefix=scheduling-
spring.task.scheduling.pool.size=2
spring:
task:
scheduling:
thread-name-prefix: "scheduling-"
pool:
size: 2
如果需要建立自定義執行器或排程器,上下文中將提供一個 ThreadPoolTaskExecutorBuilder bean、一個 SimpleAsyncTaskExecutorBuilder bean、一個 ThreadPoolTaskSchedulerBuilder bean 和一個 SimpleAsyncTaskSchedulerBuilder。如果啟用了虛擬執行緒(使用 Java 21+ 且 spring.threads.virtual.enabled 設定為 true),則 SimpleAsyncTaskExecutorBuilder 和 SimpleAsyncTaskSchedulerBuilder bean 將自動配置為使用虛擬執行緒。