Skip to content

Commit 990752b

Browse files
committed
Add auto-configuration support for TaskExecutor
This commit adds support for configuring a ThreadPoolTaskExecutor as well as auto-configuration when it makes sense. A ThreadPoolTaskExecutor can be easily built using TaskExecutorBuilder that is available as a bean. The default builder can be initialized using the `spring.task.*`namespace. As the necessary classes to setup such pool are always present, only the builder is made available by default. If `@EnableAsync` is detected and no TaskExecutor was configured, the one produced by the builder is exposed automatically. See spring-projectsgh-1563
1 parent 76d44ca commit 990752b

File tree

10 files changed

+839
-0
lines changed

10 files changed

+839
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2012-2018 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+
* http://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.autoconfigure.scheduling;
18+
19+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
20+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
21+
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
24+
import org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration;
25+
import org.springframework.boot.task.TaskExecutorBuilder;
26+
import org.springframework.context.annotation.Bean;
27+
import org.springframework.context.annotation.Conditional;
28+
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.core.task.TaskExecutor;
30+
import org.springframework.scheduling.annotation.AsyncConfigurer;
31+
import org.springframework.scheduling.annotation.EnableAsync;
32+
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
33+
import org.springframework.scheduling.config.TaskManagementConfigUtils;
34+
35+
/**
36+
* {@link EnableAutoConfiguration Auto-configuration} for scheduling.
37+
*
38+
* @author Stephane Nicoll
39+
* @since 2.1.0
40+
* @see EnableAsync
41+
*/
42+
@Configuration
43+
@ConditionalOnMissingBean(TaskExecutor.class)
44+
@AutoConfigureAfter(TaskExecutorAutoConfiguration.class)
45+
public class SchedulingAutoConfiguration {
46+
47+
@Configuration
48+
@Conditional(EnableAsyncAvailableCondition.class)
49+
@ConditionalOnMissingBean(AsyncConfigurer.class)
50+
static class AsyncConfiguration {
51+
52+
@Bean
53+
public ThreadPoolTaskExecutor taskExecutor(TaskExecutorBuilder builder) {
54+
return builder.build();
55+
}
56+
57+
}
58+
59+
static class EnableAsyncAvailableCondition extends AnyNestedCondition {
60+
61+
EnableAsyncAvailableCondition() {
62+
super(ConfigurationPhase.REGISTER_BEAN);
63+
}
64+
65+
@ConditionalOnBean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
66+
static class ProxyMode {
67+
68+
}
69+
70+
@ConditionalOnBean(name = TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)
71+
static class AspectJMode {
72+
73+
}
74+
75+
}
76+
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2012-2018 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+
* http://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.autoconfigure.task;
18+
19+
import java.util.stream.Collectors;
20+
21+
import org.springframework.beans.factory.ObjectProvider;
22+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
25+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
26+
import org.springframework.boot.task.TaskExecutorBuilder;
27+
import org.springframework.boot.task.TaskExecutorCustomizer;
28+
import org.springframework.context.annotation.Bean;
29+
import org.springframework.context.annotation.Configuration;
30+
import org.springframework.core.task.TaskDecorator;
31+
import org.springframework.core.task.TaskExecutor;
32+
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
33+
34+
/**
35+
* {@link EnableAutoConfiguration Auto-configuration} for {@link TaskExecutor}.
36+
*
37+
* @author Stephane Nicoll
38+
* @since 2.1.0
39+
*/
40+
@ConditionalOnClass(ThreadPoolTaskExecutor.class)
41+
@Configuration
42+
@EnableConfigurationProperties(TaskProperties.class)
43+
public class TaskExecutorAutoConfiguration {
44+
45+
private final TaskProperties properties;
46+
47+
private final ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers;
48+
49+
private final ObjectProvider<TaskDecorator> taskDecorator;
50+
51+
public TaskExecutorAutoConfiguration(TaskProperties properties,
52+
ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers,
53+
ObjectProvider<TaskDecorator> taskDecorator) {
54+
this.properties = properties;
55+
this.taskExecutorCustomizers = taskExecutorCustomizers;
56+
this.taskDecorator = taskDecorator;
57+
}
58+
59+
@Bean
60+
@ConditionalOnMissingBean
61+
public TaskExecutorBuilder taskExecutorBuilder() {
62+
TaskExecutorBuilder builder = new TaskExecutorBuilder();
63+
TaskProperties.Pool pool = this.properties.getPool();
64+
builder = builder.corePoolSize(pool.getCoreSize()).maxPoolSize(pool.getMaxSize())
65+
.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout())
66+
.keepAlive(pool.getKeepAlive());
67+
builder = builder.queueCapacity(this.properties.getQueueCapacity())
68+
.threadNamePrefix(this.properties.getThreadNamePrefix());
69+
builder = builder.customizers(
70+
this.taskExecutorCustomizers.stream().collect(Collectors.toList()));
71+
TaskDecorator taskDecorator = this.taskDecorator.getIfUnique();
72+
if (taskDecorator != null) {
73+
builder = builder.taskDecorator(taskDecorator);
74+
}
75+
return builder;
76+
}
77+
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2012-2018 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+
* http://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.autoconfigure.task;
18+
19+
import java.time.Duration;
20+
21+
import org.springframework.boot.context.properties.ConfigurationProperties;
22+
23+
/**
24+
* Configuration properties for task execution.
25+
*
26+
* @author Stephane Nicoll
27+
*/
28+
@ConfigurationProperties("spring.task")
29+
public class TaskProperties {
30+
31+
private final Pool pool = new Pool();
32+
33+
private int queueCapacity = Integer.MAX_VALUE;
34+
35+
private String threadNamePrefix = "executor-";
36+
37+
public Pool getPool() {
38+
return this.pool;
39+
}
40+
41+
public int getQueueCapacity() {
42+
return this.queueCapacity;
43+
}
44+
45+
public void setQueueCapacity(int queueCapacity) {
46+
this.queueCapacity = queueCapacity;
47+
}
48+
49+
public String getThreadNamePrefix() {
50+
return this.threadNamePrefix;
51+
}
52+
53+
public void setThreadNamePrefix(String threadNamePrefix) {
54+
this.threadNamePrefix = threadNamePrefix;
55+
}
56+
57+
public static class Pool {
58+
59+
private int coreSize = 1;
60+
61+
private int maxSize = Integer.MAX_VALUE;
62+
63+
private boolean allowCoreThreadTimeout;
64+
65+
private Duration keepAlive = Duration.ofSeconds(60);
66+
67+
public int getCoreSize() {
68+
return this.coreSize;
69+
}
70+
71+
public void setCoreSize(int coreSize) {
72+
this.coreSize = coreSize;
73+
}
74+
75+
public int getMaxSize() {
76+
return this.maxSize;
77+
}
78+
79+
public void setMaxSize(int maxSize) {
80+
this.maxSize = maxSize;
81+
}
82+
83+
public boolean isAllowCoreThreadTimeout() {
84+
return this.allowCoreThreadTimeout;
85+
}
86+
87+
public void setAllowCoreThreadTimeout(boolean allowCoreThreadTimeout) {
88+
this.allowCoreThreadTimeout = allowCoreThreadTimeout;
89+
}
90+
91+
public Duration getKeepAlive() {
92+
return this.keepAlive;
93+
}
94+
95+
public void setKeepAlive(Duration keepAlive) {
96+
this.keepAlive = keepAlive;
97+
}
98+
99+
}
100+
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2018 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+
* http://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+
/**
18+
* Auto-configuration for task execution.
19+
*/
20+
package org.springframework.boot.autoconfigure.task;

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
9696
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
9797
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
9898
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
99+
org.springframework.boot.autoconfigure.scheduling.SchedulingAutoConfiguration,\
99100
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
100101
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
101102
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
@@ -106,6 +107,7 @@ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
106107
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
107108
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
108109
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
110+
org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration,\
109111
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
110112
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
111113
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\

0 commit comments

Comments
 (0)