任务执行与调度
如果上下文中没有 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
会让位,常规任务执行(通过 @EnableAsync
)将使用自定义 Executor
。
但 Spring MVC、Spring WebFlux 和 Spring GraphQL 都要求存在名为 applicationTaskExecutor
的 bean。
对于 Spring MVC 和 Spring WebFlux,该 bean 必须为 AsyncTaskExecutor
类型,而 Spring GraphQL 不强制类型要求。
Spring WebSocket 和 JPA 会在存在单个 AsyncTaskExecutor
类型 bean 或定义了名为 applicationTaskExecutor
的 bean 时使用该类型。
最后,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
。
但请记得结合使用 @Qualifier
和 @Autowired
注解。
如果无法满足上述条件,可以如下方式请求 Spring Boot 仍然自动配置 AsyncTaskExecutor
:
-
Properties
-
YAML
spring.task.execution.mode=force
spring:
task:
execution:
mode: force
自动配置的 AsyncTaskExecutor
会自动用于所有集成场景,即使注册了自定义 Executor
bean,包括被标记为 @Primary
的 bean。
这些集成场景包括:
-
异步任务执行(
@EnableAsync
),除非存在AsyncConfigurer
bean。 -
Spring for GraphQL 控制器方法返回
Callable
的异步处理。 -
Spring MVC 的异步请求处理。
-
Spring WebFlux 的阻塞执行支持。
-
Spring WebSocket 的入站和出站消息通道。
-
JPA 的引导执行器,基于 JPA 仓库的引导模式。
-
ApplicationContext
中 bean 的 后台初始化 的引导执行器,除非定义了名为bootstrapExecutor
的 bean。
根据你的目标安排,可以将 |
启用 |
当自动配置 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
,该调度器会忽略所有与池相关的属性。
未启用虚拟线程时,将使用带有合理默认值的 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
、SimpleAsyncTaskExecutorBuilder
、ThreadPoolTaskSchedulerBuilder
和 SimpleAsyncTaskSchedulerBuilder
bean。
如启用虚拟线程,SimpleAsyncTaskExecutorBuilder
和 SimpleAsyncTaskSchedulerBuilder
bean 也会自动配置为使用虚拟线程(Java 21+ 且 spring.threads.virtual.enabled
设置为 true
)。