Skip to content

Commit f3a48c8

Browse files
committed
Update documentation for Task Execution
Signed-off-by: Dmytro Nosan <[email protected]>
1 parent ab1b310 commit f3a48c8

File tree

2 files changed

+129
-12
lines changed

2 files changed

+129
-12
lines changed

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/task-execution-and-scheduling.adoc

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,59 @@ In the absence of an javadoc:java.util.concurrent.Executor[] bean in the context
55
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.
66
Otherwise, it will be a javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor[] with sensible defaults.
77

8-
If a custom `Executor` bean is present, you can request Spring Boot to auto-configure an `AsyncTaskExecutor` anyway, as follows:
8+
[NOTE]
9+
====
10+
The auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[] will be used for all
11+
integrations unless a custom javadoc:java.util.concurrent.Executor[] bean is provided.
12+
====
13+
14+
Although this works in most cases, Spring Boot provides the option to override the auto-configured
15+
javadoc:org.springframework.core.task.AsyncTaskExecutor[]. By default, when a custom
16+
javadoc:java.util.concurrent.Executor[] bean is registered, the auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[]
17+
backs off, and custom javadoc:java.util.concurrent.Executor[] will be used for regular task execution
18+
(via javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation]).
19+
However, Spring MVC, Spring WebFlux, and Spring GraphQL all require a bean named `applicationTaskExecutor`.
20+
For Spring MVC and Spring WebFlux, this bean must be of type javadoc:org.springframework.core.task.AsyncTaskExecutor[],
21+
whereas Spring GraphQL does not have this requirement.
22+
23+
The following code snippet demonstrates how to register a custom javadoc:org.springframework.core.task.AsyncTaskExecutor[]
24+
to be used with Spring MVC, Spring WebFlux and Spring GraphQL.
25+
26+
include-code::TaskExecutionConfigurationExamples[tag=application-task-executor]
27+
28+
[NOTE]
29+
====
30+
The `applicationTaskExecutor` above will be used for regular task execution as well if there is no `@Primary` bean
31+
or a bean named `taskExecutor` of type javadoc:java.util.concurrent.Executor[] is registered in the application context.
32+
====
33+
34+
If your application needs multiple javadoc:java.util.concurrent.Executor[] beans for different purposes and configurations,
35+
such as one for regular task execution (`@EnableAsync`) and another for Spring MVC, this can be achieved with the following configuration:
36+
37+
include-code::TaskExecutionConfigurationExamples[tag=multiple-task-executor]
38+
39+
[TIP]
40+
====
41+
The auto-configured javadoc:org.springframework.boot.task.ThreadPoolTaskExecutorBuilder[] or javadoc:org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder[] allow you to easily create instances
42+
of type javadoc:org.springframework.core.task.AsyncTaskExecutor[] that replicate the default behavior of auto-configuration.
43+
====
44+
45+
[WARNING]
46+
====
47+
If neither the auto-configured `AsyncTaskExecutor` nor the bean named `applicationTaskExecutor` is defined,
48+
only regular task execution fallbacks to a bean named `taskExecutor` to match Spring Framework's behavior.
49+
====
50+
51+
If a bean named `taskExecutor` cannot be used, you can register an
52+
javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] bean to specify which `Executor` should handle regular task execution with `@EnableAsync`.
53+
54+
To register a custom javadoc:java.util.concurrent.Executor[] while keeping the auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[],
55+
you can create a custom javadoc:java.util.concurrent.Executor[] bean and set the `defaultCandidate=false` attribute
56+
in its javadoc:org.springframework.context.annotation.Bean[format=annotation] annotation, as demonstrated in the following example.
57+
58+
include-code::TaskExecutionConfigurationExamples[tag=default-candidate-task-executor]
59+
60+
If for some reason, it is not possible, you can request Spring Boot to auto-configure an `AsyncTaskExecutor` anyway, as follows:
961

1062
[configprops,yaml]
1163
----
@@ -15,7 +67,7 @@ spring:
1567
mode: force
1668
----
1769

18-
The auto-configured executor will be automatically used for:
70+
The auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[] will be automatically used for:
1971

2072
- Asynchronous task execution (`@EnableAsync`), unless an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] bean is present.
2173
- Spring for GraphQL's asynchronous handling of javadoc:java.util.concurrent.Callable[] return values from controller methods.
@@ -24,22 +76,17 @@ The auto-configured executor will be automatically used for:
2476

2577
[TIP]
2678
====
27-
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.
28-
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`.
29-
3079
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[].
31-
32-
Another option is to define those beans explicitly.
33-
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.
3480
====
3581

36-
[NOTE]
82+
[WARNING]
3783
====
38-
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`.
39-
If the auto-configured `AsyncTaskExecutor` is not defined, only regular task execution fallbacks to a bean named `taskExecutor` to match Spring Framework's behavior.
84+
When `force` mode is enabled, `applicationTaskExecutor` will also be configured for regular
85+
task execution with `@EnableAsync`, even if a `@Primary` bean or a bean named `taskExecutor`
86+
of type javadoc:java.util.concurrent.Executor[] is present. The only way to override the `Executor`
87+
for regular tasks is by registering an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] bean.
4088
====
4189

42-
4390
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.
4491
Those default settings can be fine-tuned using the `spring.task.execution` namespace, as shown in the following example:
4592

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docs.features.taskexecutionandscheduling;
18+
19+
import java.util.concurrent.Executors;
20+
import java.util.concurrent.ScheduledExecutorService;
21+
22+
import org.springframework.beans.factory.annotation.Qualifier;
23+
import org.springframework.context.annotation.Bean;
24+
import org.springframework.core.task.SimpleAsyncTaskExecutor;
25+
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
26+
27+
public class TaskExecutionConfigurationExamples {
28+
29+
static class TaskExecutorWithDefaultCandidate {
30+
31+
// tag::default-candidate-task-executor[]
32+
@Bean(defaultCandidate = false)
33+
@Qualifier("myScheduler")
34+
ScheduledExecutorService myScheduler() {
35+
return Executors.newSingleThreadScheduledExecutor();
36+
}
37+
// end::default-candidate-task-executor[]
38+
39+
}
40+
41+
static class ApplicationTaskExecutor {
42+
43+
// tag::application-task-executor[]
44+
@Bean("applicationTaskExecutor")
45+
SimpleAsyncTaskExecutor applicationTaskExecutor() {
46+
return new SimpleAsyncTaskExecutor("my-app-");
47+
}
48+
// end::application-task-executor[]
49+
50+
}
51+
52+
static class MultipleTaskExecutor {
53+
54+
// tag::multiple-task-executor[]
55+
@Bean("applicationTaskExecutor")
56+
SimpleAsyncTaskExecutor applicationTaskExecutor() {
57+
return new SimpleAsyncTaskExecutor("spring-mvc-");
58+
}
59+
60+
@Bean("taskExecutor")
61+
ThreadPoolTaskExecutor taskExecutor() {
62+
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
63+
threadPoolTaskExecutor.setThreadNamePrefix("enable-async-");
64+
return threadPoolTaskExecutor;
65+
}
66+
// end::multiple-task-executor[]
67+
68+
}
69+
70+
}

0 commit comments

Comments
 (0)