任务执行与调度
在上下文中没有 Executor bean 的情况下,Spring Boot 会自动配置一个 AsyncTaskExecutor。当启用了虚拟线程(使用 Java 21+ 并将 spring.threads.virtual.enabled
设置为 true
)时,这将是一个使用虚拟线程的 SimpleAsyncTaskExecutor。否则,它将是一个具有合理默认值的 ThreadPoolTaskExecutor。无论哪种情况,自动配置的执行器都将自动用于以下场景:
-
异步任务执行(
@EnableAsync
) -
Spring for GraphQL 对控制器方法返回的 Callable 值的异步处理
-
Spring MVC 的异步请求处理
-
Spring WebFlux 的阻塞执行支持
如果你在上下文中定义了一个自定义的 Executor,那么常规任务执行(即 @EnableAsync)和 Spring for GraphQL 都会使用它。然而,Spring MVC 和 Spring WebFlux 支持只有在它是一个 AsyncTaskExecutor 实现(命名为 applicationTaskExecutor
)时才会使用它。根据你的目标配置,你可以将你的 Executor 转换为 AsyncTaskExecutor,或者同时定义一个 AsyncTaskExecutor 和一个 AsyncConfigurer 来包装你的自定义 Executor。
自动配置的 ThreadPoolTaskExecutorBuilder 允许你轻松创建实例,这些实例会重现自动配置默认的行为。
当 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 bean。如果启用了虚拟线程(使用 Java 21+ 且 spring.threads.virtual.enabled
设置为 true
),SimpleAsyncTaskExecutorBuilder 和 SimpleAsyncTaskSchedulerBuilder bean 将自动配置为使用虚拟线程。