此版本仍在开发中,尚未被视为稳定版本。如需最新稳定版本,请使用 Spring Boot 4.0.4!spring-doc.cadn.net.cn

任务执行与调度

若上下文中不存在 Executor 类型的 Bean,Spring Boot 将自动配置一个 AsyncTaskExecutor。 当启用虚拟线程(使用 Java 21 或更高版本,并将 spring.threads.virtual.enabled 设置为 true)时,该实例将是一个基于虚拟线程的 SimpleAsyncTaskExecutor。 否则,它将是一个具有合理默认配置的 ThreadPoolTaskExecutorspring-doc.cadn.net.cn

除非定义了自定义的 Executor Bean,否则以下集成将使用自动配置的 AsyncTaskExecutorspring-doc.cadn.net.cn

虽然该方法在大多数场景下均有效,但 Spring Boot 允许您覆盖自动配置的 AsyncTaskExecutor。 默认情况下,当注册自定义的 Executor Bean 时,自动配置的 AsyncTaskExecutor 将自动退出,而自定义的 Executor 将用于常规任务执行(通过 @EnableAsync)。spring-doc.cadn.net.cn

然而,Spring MVC、Spring WebFlux 和 Spring GraphQL 均需要一个名为 applicationTaskExecutor 的 Bean。 对于 Spring MVC 和 Spring WebFlux,该 Bean 必须是 AsyncTaskExecutor 类型;而 Spring GraphQL 并不限制此类型要求。spring-doc.cadn.net.cn

Spring WebSocket 和 JPA 将使用 AsyncTaskExecutor,前提是此类的单个 Bean 可用,或者已定义名称为 applicationTaskExecutor 的 Bean。spring-doc.cadn.net.cn

最后,ApplicationContext 的引导执行器会使用名为 applicationTaskExecutor 的 Bean,除非已定义了名为 bootstrapExecutor 的 Bean。spring-doc.cadn.net.cn

以下代码片段演示了如何注册一个自定义的 AsyncTaskExecutor,以便在 Spring MVC、Spring WebFlux、Spring GraphQL、Spring WebSocket、JPA 以及 Bean 的后台初始化中使用。spring-doc.cadn.net.cn

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-")
	}

}

如果应用程序上下文中不存在@Primary类型的Bean,也不存在名称为taskExecutor、类型为ExecutorAsyncConfigurer的Bean,则applicationTaskExecutor类型的Bean也将用于常规任务执行。spring-doc.cadn.net.cn

如果既未定义自动配置的 AsyncTaskExecutor Bean,也未定义 applicationTaskExecutor Bean,则应用程序将默认使用名为 taskExecutor 的 Bean 执行常规任务(@EnableAsync),该行为遵循 Spring 框架的约定。 然而,此 Bean 不会用于 Spring MVC、Spring WebFlux 或 Spring GraphQL。 但如果该 Bean 的类型为 AsyncTaskExecutor,则仍可用于 Spring WebSocket 或 JPA。spring-doc.cadn.net.cn

如果您的应用程序需要为不同的集成配置多个 Executor Bean,例如一个用于配合 @EnableAsync 执行常规任务,另一个用于 Spring MVC、Spring WebFlux、Spring WebSocket 和 JPA,则可以按如下方式配置它们。spring-doc.cadn.net.cn

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
	}

}

自动配置的 ThreadPoolTaskExecutorBuilderSimpleAsyncTaskExecutorBuilder 可帮助您轻松创建类型为 AsyncTaskExecutor 的实例,以复现自动配置的默认行为。spring-doc.cadn.net.cn

import org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder;
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
	SimpleAsyncTaskExecutor taskExecutor(SimpleAsyncTaskExecutorBuilder builder) {
		return builder.build();
	}

}
import org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.task.SimpleAsyncTaskExecutor

@Configuration(proxyBeanMethods = false)
class MyTaskExecutorConfiguration {

	@Bean
	fun taskExecutor(builder: SimpleAsyncTaskExecutorBuilder): SimpleAsyncTaskExecutor {
		return builder.build()
	}

}

如果名为 taskExecutor 的 Bean 不可行,您可以将您的 Bean 标记为 @Primary,或定义一个 AsyncConfigurer Bean,以指定负责使用 @EnableAsync 处理常规任务执行的 Executor。 以下示例演示了如何实现这一点。spring-doc.cadn.net.cn

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 属性,如下例所示:spring-doc.cadn.net.cn

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 注解的同时配合使用 @Autowiredspring-doc.cadn.net.cn

如果这对您来说不可行,您仍可按如下方式请求 Spring Boot 自动配置一个 AsyncTaskExecutorspring-doc.cadn.net.cn

spring.task.execution.mode=force
spring:
  task:
    execution:
      mode: force

自动配置的 AsyncTaskExecutor 将被自动用于所有集成,即使注册了自定义的 Executor Bean(包括标记为 @Primary 的 Bean)也不例外。 这些集成包括:spring-doc.cadn.net.cn

根据您的目标配置,您可以将 spring.task.execution.mode 设置为 force 以自动配置一个 applicationTaskExecutor,将您的 Executor 更改为 AsyncTaskExecutor,或者同时定义一个 AsyncTaskExecutor 和一个 AsyncConfigurer,用它们来包装您自定义的 Executorspring-doc.cadn.net.cn

当启用 force 模式时,即使存在一个 @Primary 类型的 Bean,或存在一个类型为 Executor、名称为 taskExecutor 的 Bean,applicationTaskExecutor 仍会通过 @EnableAsync 配置用于常规任务执行。 覆盖常规任务所用 Executor 的唯一方法是注册一个 AsyncConfigurer 类型的 Bean。spring-doc.cadn.net.cn

当自动配置一个 ThreadPoolTaskExecutor 时,线程池将使用 8 个核心线程,并可根据负载动态增减线程数量。 这些默认设置可通过 spring.task.execution 命名空间进行微调,如下例所示:spring-doc.cadn.net.cn

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 秒后才回收)。spring-doc.cadn.net.cn

如果调度器需要与定时任务执行相关联(例如,使用 @EnableScheduling),则该调度器也可自动配置。spring-doc.cadn.net.cn

如果启用了虚拟线程(使用 Java 21+ 且将 spring.threads.virtual.enabled 设置为 true),则此处将是一个使用虚拟线程的 SimpleAsyncTaskScheduler。 该 SimpleAsyncTaskScheduler 将忽略所有与线程池相关的属性。spring-doc.cadn.net.cn

如果未启用虚拟线程,则将使用一个具有合理默认值的 ThreadPoolTaskSchedulerThreadPoolTaskScheduler 默认使用一个线程,其设置可通过 spring.task.scheduling 命名空间进行精细调整,如下例所示:spring-doc.cadn.net.cn

spring.task.scheduling.thread-name-prefix=scheduling-
spring.task.scheduling.pool.size=2
spring:
  task:
    scheduling:
      thread-name-prefix: "scheduling-"
      pool:
        size: 2

如果需要创建自定义执行器(executor)或调度器(scheduler),则上下文中会提供一个 ThreadPoolTaskExecutorBuilder 类型的 Bean、一个 SimpleAsyncTaskExecutorBuilder 类型的 Bean、一个 ThreadPoolTaskSchedulerBuilder 类型的 Bean 以及一个 SimpleAsyncTaskSchedulerBuilder 类型的 Bean。 当启用虚拟线程时(需使用 Java 21 或更高版本,且将 spring.threads.virtual.enabled 设置为 true),SimpleAsyncTaskExecutorBuilderSimpleAsyncTaskSchedulerBuilder 这两个 Bean 将自动配置为使用虚拟线程。spring-doc.cadn.net.cn