Update documentation for Task Execution
See gh-44926 Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>
This commit is contained in:
parent
e39ce56707
commit
6a92364ccd
|
@ -5,7 +5,76 @@ In the absence of an javadoc:java.util.concurrent.Executor[] bean in the context
|
||||||
When virtual threads are enabled (using Java 21+ and configprop:spring.threads.virtual.enabled[] set to `true`) this will be a javadoc:org.springframework.core.task.SimpleAsyncTaskExecutor[] that uses virtual threads.
|
When virtual threads are enabled (using Java 21+ and configprop:spring.threads.virtual.enabled[] set to `true`) this will be a javadoc:org.springframework.core.task.SimpleAsyncTaskExecutor[] that uses virtual threads.
|
||||||
Otherwise, it will be a javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor[] with sensible defaults.
|
Otherwise, it will be a javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor[] with sensible defaults.
|
||||||
|
|
||||||
If a custom `Executor` bean is present, you can request Spring Boot to auto-configure an `AsyncTaskExecutor` anyway, as follows:
|
The auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[] is used for the following integrations unless a custom javadoc:java.util.concurrent.Executor[] bean is defined:
|
||||||
|
|
||||||
|
- Execution of asynchronous tasks using javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation], unless a bean of type javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] is defined.
|
||||||
|
- Asynchronous handling of javadoc:java.util.concurrent.Callable[] return values from controller methods in Spring for GraphQL.
|
||||||
|
- Asynchronous request handling in Spring MVC.
|
||||||
|
- Support for blocking execution in Spring WebFlux.
|
||||||
|
- Utilized for inbound and outbound message channels in Spring WebSocket.
|
||||||
|
- Acts as a bootstrap executor for JPA, based on the bootstrap mode of JPA repositories.
|
||||||
|
|
||||||
|
While this approach works in most scenarios, Spring Boot allows you to override the auto-configured
|
||||||
|
javadoc:org.springframework.core.task.AsyncTaskExecutor[].
|
||||||
|
By default, when a custom javadoc:java.util.concurrent.Executor[] bean is registered, the auto-configured
|
||||||
|
javadoc:org.springframework.core.task.AsyncTaskExecutor[] steps aside, and the custom javadoc:java.util.concurrent.Executor[] is used for regular task execution (via javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation]).
|
||||||
|
|
||||||
|
However, Spring MVC, Spring WebFlux, and Spring GraphQL all require a bean named `applicationTaskExecutor`.
|
||||||
|
For Spring MVC and Spring WebFlux, this bean must be of type javadoc:org.springframework.core.task.AsyncTaskExecutor[], whereas Spring GraphQL does not enforce this type requirement.
|
||||||
|
|
||||||
|
Spring WebSocket and JPA will use javadoc:org.springframework.core.task.AsyncTaskExecutor[] if either a single bean of this type is available or a bean named `applicationTaskExecutor` is defined.
|
||||||
|
|
||||||
|
The following code snippet demonstrates how to register a custom javadoc:org.springframework.core.task.AsyncTaskExecutor[]
|
||||||
|
to be used with Spring MVC, Spring WebFlux, Spring GraphQL, Spring WebSocket and JPA.
|
||||||
|
|
||||||
|
include-code::TaskExecutionConfigurationExamples[tag=application-task-executor]
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
====
|
||||||
|
The `applicationTaskExecutor` bean will also be used for regular task execution if there is no
|
||||||
|
javadoc:org.springframework.context.annotation.Primary[format=annotation] bean or a bean named `taskExecutor` of type javadoc:java.util.concurrent.Executor[]
|
||||||
|
or javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] present in the application context.
|
||||||
|
====
|
||||||
|
|
||||||
|
[WARNING]
|
||||||
|
====
|
||||||
|
If neither the auto-configured `AsyncTaskExecutor` nor the `applicationTaskExecutor` bean is defined, the application defaults to a bean named `taskExecutor` for regular task execution (javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation]), following Spring Framework's behavior.
|
||||||
|
However, this bean will not be used for Spring MVC, Spring WebFlux, Spring GraphQL.
|
||||||
|
It could, however, be used for Spring WebSocket or JPA if bean's type is javadoc:org.springframework.core.task.AsyncTaskExecutor[].
|
||||||
|
====
|
||||||
|
|
||||||
|
If your application needs multiple `Executor` beans for different integrations, such as one for regular task execution with javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation]
|
||||||
|
and other for Spring MVC, Spring WebFlux, Spring WebSocket and JPA you can configure them as follows.
|
||||||
|
|
||||||
|
include-code::TaskExecutionConfigurationExamples[tag=multiple-task-executor]
|
||||||
|
|
||||||
|
[TIP]
|
||||||
|
====
|
||||||
|
The auto-configured javadoc:org.springframework.boot.task.ThreadPoolTaskExecutorBuilder[] or
|
||||||
|
javadoc:org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder[] allow you to easily create instances of type javadoc:org.springframework.core.task.AsyncTaskExecutor[] that replicate the default behavior of auto-configuration.
|
||||||
|
|
||||||
|
include-code::TaskExecutionConfigurationExamples[tag=executor-builder]
|
||||||
|
====
|
||||||
|
|
||||||
|
If a `taskExecutor` named bean is not an option, you can mark your bean as javadoc:org.springframework.context.annotation.Primary[format=annotation] or define an
|
||||||
|
javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] bean to specify the
|
||||||
|
`Executor` responsible for handling regular task execution with javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation].
|
||||||
|
The following example demonstrates how to achieve this.
|
||||||
|
|
||||||
|
include-code::TaskExecutionConfigurationExamples[tag=async-configurer]
|
||||||
|
|
||||||
|
To register a custom javadoc:java.util.concurrent.Executor[] while keeping the auto-configured
|
||||||
|
javadoc:org.springframework.core.task.AsyncTaskExecutor[], you can create a custom
|
||||||
|
javadoc:java.util.concurrent.Executor[] bean and set the `defaultCandidate=false` attribute in its
|
||||||
|
javadoc:org.springframework.context.annotation.Bean[format=annotation] annotation, as demonstrated in the following example:
|
||||||
|
|
||||||
|
include-code::TaskExecutionConfigurationExamples[tag=default-candidate-task-executor]
|
||||||
|
|
||||||
|
In that case, you will be able to javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation]
|
||||||
|
your custom javadoc:java.util.concurrent.Executor[] into other components while retaining the auto-configured `AsyncTaskExecutor`.
|
||||||
|
However, remember to use the javadoc:org.springframework.beans.factory.annotation.Qualifier[format=annotation] annotation alongside javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation].
|
||||||
|
|
||||||
|
If for some reason, it is not possible, you can request Spring Boot to auto-configure an `AsyncTaskExecutor` anyway, as follows:
|
||||||
|
|
||||||
[configprops,yaml]
|
[configprops,yaml]
|
||||||
----
|
----
|
||||||
|
@ -15,31 +84,27 @@ spring:
|
||||||
mode: force
|
mode: force
|
||||||
----
|
----
|
||||||
|
|
||||||
The auto-configured executor will be automatically used for:
|
The auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[] will be used automatically for all integrations, even if a custom javadoc:java.util.concurrent.Executor[] bean is registered, including those marked as javadoc:org.springframework.context.annotation.Primary[format=annotation].
|
||||||
|
These integrations include:
|
||||||
|
|
||||||
- Asynchronous task execution (`@EnableAsync`), unless an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] bean is present.
|
- Asynchronous task execution (javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation]), unless an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] bean is present.
|
||||||
- Spring for GraphQL's asynchronous handling of javadoc:java.util.concurrent.Callable[] return values from controller methods.
|
- Spring for GraphQL's asynchronous handling of javadoc:java.util.concurrent.Callable[] return values from controller methods.
|
||||||
- Spring MVC's asynchronous request processing.
|
- Spring MVC's asynchronous request processing.
|
||||||
- Spring WebFlux's blocking execution support.
|
- Spring WebFlux's blocking execution support.
|
||||||
|
- Utilized for inbound and outbound message channels in Spring WebSocket.
|
||||||
|
- Acts as a bootstrap executor for JPA, based on the bootstrap mode of JPA repositories.
|
||||||
|
|
||||||
[TIP]
|
[TIP]
|
||||||
====
|
====
|
||||||
If you have defined a custom javadoc:java.util.concurrent.Executor[] in the context, both regular task execution (that is javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation]) and Spring for GraphQL will use it.
|
|
||||||
However, the Spring MVC and Spring WebFlux support will only use it if it is an javadoc:org.springframework.core.task.AsyncTaskExecutor[] implementation named `applicationTaskExecutor`.
|
|
||||||
|
|
||||||
Depending on your target arrangement, you could set configprop:spring.task.execution.mode[] to `force` to auto-configure an `applicationTaskExecutor`, change your javadoc:java.util.concurrent.Executor[] into an javadoc:org.springframework.core.task.AsyncTaskExecutor[] or define both an javadoc:org.springframework.core.task.AsyncTaskExecutor[] and an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] wrapping your custom javadoc:java.util.concurrent.Executor[].
|
Depending on your target arrangement, you could set configprop:spring.task.execution.mode[] to `force` to auto-configure an `applicationTaskExecutor`, change your javadoc:java.util.concurrent.Executor[] into an javadoc:org.springframework.core.task.AsyncTaskExecutor[] or define both an javadoc:org.springframework.core.task.AsyncTaskExecutor[] and an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] wrapping your custom javadoc:java.util.concurrent.Executor[].
|
||||||
|
|
||||||
Another option is to define those beans explicitly.
|
|
||||||
The auto-configured javadoc:org.springframework.boot.task.ThreadPoolTaskExecutorBuilder[] or javadoc:org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder[] allow you to easily create instances that reproduce what the auto-configuration does by default.
|
|
||||||
====
|
====
|
||||||
|
|
||||||
[NOTE]
|
[WARNING]
|
||||||
====
|
====
|
||||||
If multiple javadoc:java.util.concurrent.Executor[] beans are defined with configprop:spring.task.execution.mode[] to `force`, all the supported integrations look for a bean named `applicationTaskExecutor`.
|
When `force` mode is enabled, `applicationTaskExecutor` will also be configured for regular task execution with javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation], even if a javadoc:org.springframework.context.annotation.Primary[format=annotation] bean or a bean named `taskExecutor` of type javadoc:java.util.concurrent.Executor[] is present.
|
||||||
If the auto-configured `AsyncTaskExecutor` is not defined, only regular task execution fallbacks to a bean named `taskExecutor` to match Spring Framework's behavior.
|
The only way to override the `Executor` for regular tasks is by registering an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] bean.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
|
||||||
When a javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor[] is auto-configured, the thread pool uses 8 core threads that can grow and shrink according to the load.
|
When a javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor[] is auto-configured, the thread pool uses 8 core threads that can grow and shrink according to the load.
|
||||||
Those default settings can be fine-tuned using the `spring.task.execution` namespace, as shown in the following example:
|
Those default settings can be fine-tuned using the `spring.task.execution` namespace, as shown in the following example:
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2025 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.docs.features.taskexecutionandscheduling;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||||
|
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
|
||||||
|
public class TaskExecutionConfigurationExamples {
|
||||||
|
|
||||||
|
// tag::default-candidate-task-executor[]
|
||||||
|
@Bean(defaultCandidate = false)
|
||||||
|
@Qualifier("scheduledExecutorService")
|
||||||
|
ScheduledExecutorService scheduledExecutorService() {
|
||||||
|
return Executors.newSingleThreadScheduledExecutor();
|
||||||
|
}
|
||||||
|
// end::default-candidate-task-executor[]
|
||||||
|
|
||||||
|
// tag::application-task-executor[]
|
||||||
|
@Bean("applicationTaskExecutor")
|
||||||
|
SimpleAsyncTaskExecutor applicationTaskExecutor() {
|
||||||
|
return new SimpleAsyncTaskExecutor("app-");
|
||||||
|
}
|
||||||
|
// end::application-task-executor[]
|
||||||
|
|
||||||
|
// tag::executor-builder[]
|
||||||
|
@Bean
|
||||||
|
SimpleAsyncTaskExecutor taskExecutor(SimpleAsyncTaskExecutorBuilder builder) {
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
// end::executor-builder[]
|
||||||
|
|
||||||
|
static class MultipleTaskExecutor {
|
||||||
|
|
||||||
|
// tag::multiple-task-executor[]
|
||||||
|
@Bean("applicationTaskExecutor")
|
||||||
|
SimpleAsyncTaskExecutor applicationTaskExecutor() {
|
||||||
|
return new SimpleAsyncTaskExecutor("app-");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("taskExecutor")
|
||||||
|
ThreadPoolTaskExecutor taskExecutor() {
|
||||||
|
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
|
||||||
|
threadPoolTaskExecutor.setThreadNamePrefix("async-");
|
||||||
|
return threadPoolTaskExecutor;
|
||||||
|
}
|
||||||
|
// end::multiple-task-executor[]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// tag::async-configurer[]
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
public class TaskExecutionConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
AsyncConfigurer asyncConfigurer(ExecutorService executorService) {
|
||||||
|
return new AsyncConfigurer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Executor getAsyncExecutor() {
|
||||||
|
return executorService;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ExecutorService executorService() {
|
||||||
|
return Executors.newCachedThreadPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// end::async-configurer[]
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue