|
对于最新稳定版本,请使用 Spring Boot 4.0.4! |
任务执行与调度
如果上下文中不存在 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中的入站和出站消息通道。
-
Bootstrap执行器 for JPA,基于JPA仓库的bootstrap模式。
-
Bootstrap 执行器用于 在 ApplicationContext 中后台初始化 beans。
虽然这种方法在大多数场景下都有效,但 Spring Boot 允许您覆盖自动配置的 AsyncTaskExecutor。
默认情况下,当注册了自定义的 Executor Bean 时,自动配置的 AsyncTaskExecutor 会退避,此时将使用自定义的 Executor 来执行常规任务(通过 @EnableAsync)。
然而,Spring MVC、Spring WebFlux 和 Spring GraphQL 都需要一个名为 applicationTaskExecutor 的 Bean。
对于 Spring MVC 和 Spring WebFlux,此 Bean 的类型必须为 AsyncTaskExecutor,而 Spring GraphQL 并不强制要求此类型。
Spring WebSocket 和 JPA 将在存在该类型的单个 Bean 或定义了名为 applicationTaskExecutor 的 Bean 时使用 AsyncTaskExecutor。
最终,ApplicationContext 的 boostrap 执行器会使用名为 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()
}
}
要注册自定义的 Executor,同时保留自动配置的 AsyncTaskExecutor,您可以创建一个自定义的 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,如下所示:
-
Properties
-
YAML
spring.task.execution.mode=force
spring:
task:
execution:
mode: force
自动配置的 AsyncTaskExecutor 将自动用于所有集成,即使注册了自定义的 Executor Bean(包括标记为 @Primary 的 Bean)。
这些集成包括:
-
异步任务执行(
@EnableAsync),除非存在AsyncConfigurerbean。 -
Spring for GraphQL 对控制器方法中
Callable返回值的异步处理。 -
Spring MVC 的异步请求处理。
-
Spring WebFlux 的阻塞执行支持。
-
用于Spring WebSocket中的入站和出站消息通道。
-
Bootstrap执行器 for JPA,基于JPA仓库的bootstrap模式。
-
Bootstrap executor for 后台初始化 of beans in the
ApplicationContext, unless a bean namedbootstrapExecutoris defined.
|
根据您的目标配置,您可以将 |
|
当启用 |
当 ThreadPoolTaskExecutor 被自动配置时,线程池将使用 8 个核心线程,这些线程可根据负载动态增减。
可以使用 spring.task.execution 命名空间对这些默认设置进行微调,如下例所示:
-
Properties
-
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 命名空间进行微调,如下例所示:
-
Properties
-
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 会自动配置为使用虚拟线程。