Skip to content

Commit 72a1661

Browse files
committed
Add auto-configuration for general use TaskExecutor
1 parent 725ae2c commit 72a1661

File tree

7 files changed

+361
-0
lines changed

7 files changed

+361
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2012-2016 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 org.springframework.boot.autoconfigure.AutoConfigureBefore;
20+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
23+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.core.task.TaskExecutor;
27+
import org.springframework.scheduling.concurrent.DefaultManagedTaskExecutor;
28+
29+
/**
30+
* {@link EnableAutoConfiguration Auto-configuration} for a JNDI located
31+
* {@link TaskExecutor}.
32+
*
33+
* @author Vedran Pavic
34+
* @since 1.4.0
35+
*/
36+
@Configuration
37+
@AutoConfigureBefore(TaskExecutorAutoConfiguration.class)
38+
@ConditionalOnProperty(prefix = "spring.task", name = "jndi-name")
39+
@EnableConfigurationProperties(TaskExecutorProperties.class)
40+
public class JndiTaskExecutorAutoConfiguration {
41+
42+
@Bean
43+
@ConditionalOnMissingBean
44+
public TaskExecutor taskExecutor(TaskExecutorProperties properties) {
45+
DefaultManagedTaskExecutor taskExecutor = new DefaultManagedTaskExecutor();
46+
taskExecutor.setJndiName(properties.getJndiName());
47+
return taskExecutor;
48+
}
49+
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2012-2016 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.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
20+
21+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
23+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.core.task.TaskExecutor;
27+
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
28+
29+
/**
30+
* {@link EnableAutoConfiguration Auto-configuration} for {@link TaskExecutor}.
31+
*
32+
* @author Vedran Pavic
33+
* @since 1.4.0
34+
*/
35+
@Configuration
36+
@EnableConfigurationProperties(TaskExecutorProperties.class)
37+
public class TaskExecutorAutoConfiguration {
38+
39+
@Bean
40+
@ConditionalOnMissingBean
41+
public TaskExecutor taskExecutor(TaskExecutorProperties properties) {
42+
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
43+
taskExecutor.setMaxPoolSize(properties.getPool().getMaxSize());
44+
taskExecutor.setThreadNamePrefix("task-executor-");
45+
taskExecutor.setRejectedExecutionHandler(new CallerRunsPolicy());
46+
return taskExecutor;
47+
}
48+
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2012-2016 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 org.springframework.boot.context.properties.ConfigurationProperties;
20+
21+
/**
22+
* Configuration properties for the task executor.
23+
*
24+
* @author Vedran Pavic
25+
* @since 1.4.0
26+
*/
27+
@ConfigurationProperties(prefix = "spring.task")
28+
public class TaskExecutorProperties {
29+
30+
/**
31+
* JNDI location of the executor to delegate to.
32+
*/
33+
private String jndiName;
34+
35+
private Pool pool = new Pool();
36+
37+
public String getJndiName() {
38+
return this.jndiName;
39+
}
40+
41+
public void setJndiName(String jndiName) {
42+
this.jndiName = jndiName;
43+
}
44+
45+
public Pool getPool() {
46+
return this.pool;
47+
}
48+
49+
public static class Pool {
50+
51+
/**
52+
* Maximum pool size for the executor.
53+
*/
54+
private Integer maxSize = 10;
55+
56+
public Integer getMaxSize() {
57+
return this.maxSize;
58+
}
59+
60+
public void setMaxSize(Integer maxSize) {
61+
this.maxSize = maxSize;
62+
}
63+
64+
}
65+
66+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2016 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 TaskExecutor.
19+
*/
20+
package org.springframework.boot.autoconfigure.task;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
8484
org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\
8585
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
8686
org.springframework.boot.autoconfigure.velocity.VelocityAutoConfiguration,\
87+
org.springframework.boot.autoconfigure.task.JndiTaskExecutorAutoConfiguration,\
88+
org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration,\
8789
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
8890
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
8991
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright 2012-2016 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.concurrent.ExecutorService;
20+
import java.util.concurrent.Executors;
21+
22+
import javax.naming.Context;
23+
import javax.naming.NamingException;
24+
25+
import org.junit.After;
26+
import org.junit.Before;
27+
import org.junit.Test;
28+
29+
import org.springframework.boot.autoconfigure.jndi.JndiPropertiesHidingClassLoader;
30+
import org.springframework.boot.autoconfigure.jndi.TestableInitialContextFactory;
31+
import org.springframework.boot.test.util.EnvironmentTestUtils;
32+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
33+
import org.springframework.core.task.TaskExecutor;
34+
import org.springframework.scheduling.concurrent.DefaultManagedTaskExecutor;
35+
36+
import static org.assertj.core.api.Assertions.assertThat;
37+
38+
/**
39+
* Tests for {@link JndiTaskExecutorAutoConfiguration}.
40+
*
41+
* @author Vedran Pavic
42+
*/
43+
public class JndiTaskExecutorAutoConfigurationTests {
44+
45+
private final AnnotationConfigApplicationContext context =
46+
new AnnotationConfigApplicationContext();
47+
48+
private String initialContextFactory;
49+
50+
private ClassLoader threadContextClassLoader;
51+
52+
@Before
53+
public void setupJndi() {
54+
this.initialContextFactory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
55+
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
56+
TestableInitialContextFactory.class.getName());
57+
}
58+
59+
@Before
60+
public void setupThreadContextClassLoader() {
61+
this.threadContextClassLoader = Thread.currentThread().getContextClassLoader();
62+
Thread.currentThread().setContextClassLoader(
63+
new JndiPropertiesHidingClassLoader(getClass().getClassLoader()));
64+
}
65+
66+
@After
67+
public void close() {
68+
TestableInitialContextFactory.clearAll();
69+
if (this.initialContextFactory != null) {
70+
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
71+
this.initialContextFactory);
72+
}
73+
else {
74+
System.clearProperty(Context.INITIAL_CONTEXT_FACTORY);
75+
}
76+
if (this.context != null) {
77+
this.context.close();
78+
}
79+
Thread.currentThread().setContextClassLoader(this.threadContextClassLoader);
80+
}
81+
82+
@Test
83+
public void taskExecutorIsAvailableFromJndi()
84+
throws IllegalStateException, NamingException {
85+
ExecutorService executorService = Executors.newSingleThreadExecutor();
86+
configureJndi("foo", executorService);
87+
88+
EnvironmentTestUtils.addEnvironment(this.context, "spring.task.jndi-name=foo");
89+
registerAndRefresh(JndiTaskExecutorAutoConfiguration.class);
90+
91+
assertThat(this.context.getBean(TaskExecutor.class))
92+
.isInstanceOf(DefaultManagedTaskExecutor.class);
93+
}
94+
95+
private void configureJndi(String name, ExecutorService executorService)
96+
throws IllegalStateException, NamingException {
97+
TestableInitialContextFactory.bind(name, executorService);
98+
}
99+
100+
private void registerAndRefresh(Class<?>... annotatedClasses) {
101+
this.context.register(annotatedClasses);
102+
this.context.refresh();
103+
}
104+
105+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2012-2016 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 org.junit.After;
20+
import org.junit.Test;
21+
22+
import org.springframework.boot.test.util.EnvironmentTestUtils;
23+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
24+
import org.springframework.core.task.TaskExecutor;
25+
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
29+
/**
30+
* Tests for {@link TaskExecutorAutoConfiguration}.
31+
*
32+
* @author Vedran Pavic
33+
*/
34+
public class TaskExecutorAutoConfigurationTests {
35+
36+
private final AnnotationConfigApplicationContext context =
37+
new AnnotationConfigApplicationContext();
38+
39+
@After
40+
public void close() {
41+
if (this.context != null) {
42+
this.context.close();
43+
}
44+
}
45+
46+
@Test
47+
public void defaultTaskExecutorExists() {
48+
registerAndRefresh(TaskExecutorAutoConfiguration.class);
49+
50+
assertThat(this.context.getBean(TaskExecutor.class))
51+
.isInstanceOf(ThreadPoolTaskExecutor.class);
52+
}
53+
54+
@Test
55+
public void customMaxPoolSize() {
56+
EnvironmentTestUtils.addEnvironment(this.context, "spring.task.pool.max-size=5");
57+
registerAndRefresh(TaskExecutorAutoConfiguration.class);
58+
59+
ThreadPoolTaskExecutor taskExecutor =
60+
this.context.getBean(ThreadPoolTaskExecutor.class);
61+
assertThat(taskExecutor.getMaxPoolSize()).isEqualTo(5);
62+
}
63+
64+
private void registerAndRefresh(Class<?>... annotatedClasses) {
65+
this.context.register(annotatedClasses);
66+
this.context.refresh();
67+
}
68+
69+
}

0 commit comments

Comments
 (0)