Browse Source
This commit adds support for providing a default ThreadPoolTaskScheduler with sensible defaults. A new TaskSchedulerBuilder is provided with defaults from the `spring.task.scheduler.*` namespace and can be used to create custom instances. If no custom `TaskScheduler` bean is present, `@EnableScheduling` now uses the auto-configured task scheduler. Closes gh-1397pull/14030/merge
11 changed files with 675 additions and 7 deletions
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
/* |
||||
* Copyright 2012-2018 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 |
||||
* |
||||
* http://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.autoconfigure.task; |
||||
|
||||
import java.util.stream.Collectors; |
||||
|
||||
import org.springframework.beans.factory.ObjectProvider; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||
import org.springframework.boot.task.TaskSchedulerBuilder; |
||||
import org.springframework.boot.task.TaskSchedulerCustomizer; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.scheduling.TaskScheduler; |
||||
import org.springframework.scheduling.annotation.SchedulingConfigurer; |
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
||||
import org.springframework.scheduling.config.TaskManagementConfigUtils; |
||||
|
||||
/** |
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link TaskScheduler}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 2.1.0 |
||||
*/ |
||||
@ConditionalOnClass(ThreadPoolTaskScheduler.class) |
||||
@Configuration |
||||
@EnableConfigurationProperties(TaskSchedulingProperties.class) |
||||
public class TaskSchedulingAutoConfiguration { |
||||
|
||||
@Bean |
||||
@ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME) |
||||
@ConditionalOnMissingBean({ SchedulingConfigurer.class, TaskScheduler.class }) |
||||
public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) { |
||||
return builder.build(); |
||||
} |
||||
|
||||
@Bean |
||||
@ConditionalOnMissingBean |
||||
public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties, |
||||
ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) { |
||||
return new TaskSchedulerBuilder().poolSize(properties.getPool().getSize()) |
||||
.threadNamePrefix(properties.getThreadNamePrefix()).customizers( |
||||
taskSchedulerCustomizers.stream().collect(Collectors.toList())); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
/* |
||||
* Copyright 2012-2018 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 |
||||
* |
||||
* http://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.autoconfigure.task; |
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
/** |
||||
* Configuration properties for task scheduling. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
@ConfigurationProperties("spring.task.scheduling") |
||||
public class TaskSchedulingProperties { |
||||
|
||||
private final Pool pool = new Pool(); |
||||
|
||||
/** |
||||
* Prefix to use for the names of newly created threads. |
||||
*/ |
||||
private String threadNamePrefix = "scheduling-"; |
||||
|
||||
public Pool getPool() { |
||||
return this.pool; |
||||
} |
||||
|
||||
public String getThreadNamePrefix() { |
||||
return this.threadNamePrefix; |
||||
} |
||||
|
||||
public void setThreadNamePrefix(String threadNamePrefix) { |
||||
this.threadNamePrefix = threadNamePrefix; |
||||
} |
||||
|
||||
public static class Pool { |
||||
|
||||
/** |
||||
* Maximum allowed number of threads. |
||||
*/ |
||||
private int size = 1; |
||||
|
||||
public int getSize() { |
||||
return this.size; |
||||
} |
||||
|
||||
public void setSize(int size) { |
||||
this.size = size; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,180 @@
@@ -0,0 +1,180 @@
|
||||
/* |
||||
* Copyright 2012-2018 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 |
||||
* |
||||
* http://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.autoconfigure.task; |
||||
|
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations; |
||||
import org.springframework.boot.task.TaskSchedulerCustomizer; |
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner; |
||||
import org.springframework.context.annotation.Bean; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.core.task.TaskExecutor; |
||||
import org.springframework.scheduling.TaskScheduler; |
||||
import org.springframework.scheduling.annotation.EnableScheduling; |
||||
import org.springframework.scheduling.annotation.Scheduled; |
||||
import org.springframework.scheduling.annotation.SchedulingConfigurer; |
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link TaskSchedulingAutoConfiguration}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
public class TaskSchedulingAutoConfigurationTests { |
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner() |
||||
.withUserConfiguration(TestConfiguration.class).withConfiguration( |
||||
AutoConfigurations.of(TaskSchedulingAutoConfiguration.class)); |
||||
|
||||
@Test |
||||
public void noSchedulingDoesNotExposeTaskScheduler() { |
||||
this.contextRunner.run( |
||||
(context) -> assertThat(context).doesNotHaveBean(TaskScheduler.class)); |
||||
} |
||||
|
||||
@Test |
||||
public void enableSchedulingWithNoTakExecutorAutoConfiguresOne() { |
||||
this.contextRunner |
||||
.withPropertyValues( |
||||
"spring.task.scheduling.thread-name-prefix=scheduling-test-") |
||||
.withUserConfiguration(SchedulingConfiguration.class).run((context) -> { |
||||
assertThat(context).hasSingleBean(TaskExecutor.class); |
||||
TestBean bean = context.getBean(TestBean.class); |
||||
Thread.sleep(15); |
||||
assertThat(bean.threadNames) |
||||
.allMatch((name) -> name.contains("scheduling-test-")); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
public void enableSchedulingWithNoTakExecutorAppliesCustomizers() { |
||||
this.contextRunner |
||||
.withPropertyValues( |
||||
"spring.task.scheduling.thread-name-prefix=scheduling-test-") |
||||
.withUserConfiguration(SchedulingConfiguration.class, |
||||
TaskSchedulerCustomizerConfiguration.class) |
||||
.run((context) -> { |
||||
assertThat(context).hasSingleBean(TaskExecutor.class); |
||||
TestBean bean = context.getBean(TestBean.class); |
||||
Thread.sleep(15); |
||||
assertThat(bean.threadNames) |
||||
.allMatch((name) -> name.contains("customized-scheduler-")); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
public void enableSchedulingWithExistingTakSchedulerBacksOff() { |
||||
this.contextRunner.withUserConfiguration(SchedulingConfiguration.class, |
||||
TaskSchedulerConfiguration.class).run((context) -> { |
||||
assertThat(context).hasSingleBean(TaskScheduler.class); |
||||
assertThat(context.getBean(TaskScheduler.class)) |
||||
.isInstanceOf(TestTaskScheduler.class); |
||||
TestBean bean = context.getBean(TestBean.class); |
||||
Thread.sleep(15); |
||||
assertThat(bean.threadNames).containsExactly("test-1"); |
||||
}); |
||||
} |
||||
|
||||
@Test |
||||
public void enableSchedulingWithConfigurerBacksOff() { |
||||
this.contextRunner.withUserConfiguration(SchedulingConfiguration.class, |
||||
SchedulingConfigurerConfiguration.class).run((context) -> { |
||||
assertThat(context).doesNotHaveBean(TaskScheduler.class); |
||||
TestBean bean = context.getBean(TestBean.class); |
||||
Thread.sleep(15); |
||||
assertThat(bean.threadNames).containsExactly("test-1"); |
||||
}); |
||||
} |
||||
|
||||
@Configuration |
||||
@EnableScheduling |
||||
static class SchedulingConfiguration { |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class TaskSchedulerConfiguration { |
||||
|
||||
@Bean |
||||
public TaskScheduler customTaskScheduler() { |
||||
return new TestTaskScheduler(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class TaskSchedulerCustomizerConfiguration { |
||||
|
||||
@Bean |
||||
public TaskSchedulerCustomizer testTaskSchedulerCustomizer() { |
||||
return ((taskScheduler) -> taskScheduler |
||||
.setThreadNamePrefix("customized-scheduler-")); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class SchedulingConfigurerConfiguration implements SchedulingConfigurer { |
||||
|
||||
private final TaskScheduler taskScheduler = new TestTaskScheduler(); |
||||
|
||||
@Override |
||||
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { |
||||
taskRegistrar.setScheduler(this.taskScheduler); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Configuration |
||||
static class TestConfiguration { |
||||
|
||||
@Bean |
||||
public TestBean testBean() { |
||||
return new TestBean(); |
||||
} |
||||
|
||||
} |
||||
|
||||
static class TestBean { |
||||
|
||||
private final Set<String> threadNames = new HashSet<>(); |
||||
|
||||
@Scheduled(fixedRate = 10) |
||||
public void accumulate() { |
||||
this.threadNames.add(Thread.currentThread().getName()); |
||||
} |
||||
|
||||
} |
||||
|
||||
static class TestTaskScheduler extends ThreadPoolTaskScheduler { |
||||
|
||||
TestTaskScheduler() { |
||||
setPoolSize(1); |
||||
setThreadNamePrefix("test-"); |
||||
afterPropertiesSet(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,187 @@
@@ -0,0 +1,187 @@
|
||||
/* |
||||
* Copyright 2012-2018 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 |
||||
* |
||||
* http://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.task; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.LinkedHashSet; |
||||
import java.util.Set; |
||||
|
||||
import org.springframework.boot.context.properties.PropertyMapper; |
||||
import org.springframework.scheduling.TaskScheduler; |
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.CollectionUtils; |
||||
|
||||
/** |
||||
* Builder that can be used to configure and create a {@link TaskScheduler}. Provides |
||||
* convenience methods to set common {@link ThreadPoolTaskScheduler} settings. For |
||||
* advanced configuration, consider using {@link TaskSchedulerCustomizer}. |
||||
* <p> |
||||
* In a typical auto-configured Spring Boot application this builder is available as a |
||||
* bean and can be injected whenever a {@link TaskScheduler} is needed. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 2.1.0 |
||||
*/ |
||||
public class TaskSchedulerBuilder { |
||||
|
||||
private final Integer poolSize; |
||||
|
||||
private final String threadNamePrefix; |
||||
|
||||
private final Set<TaskSchedulerCustomizer> taskSchedulerCustomizers; |
||||
|
||||
public TaskSchedulerBuilder(TaskSchedulerCustomizer... taskSchedulerCustomizers) { |
||||
Assert.notNull(taskSchedulerCustomizers, |
||||
"TaskSchedulerCustomizers must not be null"); |
||||
this.poolSize = null; |
||||
this.threadNamePrefix = null; |
||||
this.taskSchedulerCustomizers = Collections.unmodifiableSet( |
||||
new LinkedHashSet<>(Arrays.asList(taskSchedulerCustomizers))); |
||||
} |
||||
|
||||
public TaskSchedulerBuilder(Integer poolSize, String threadNamePrefix, |
||||
Set<TaskSchedulerCustomizer> taskSchedulerCustomizers) { |
||||
this.poolSize = poolSize; |
||||
this.threadNamePrefix = threadNamePrefix; |
||||
this.taskSchedulerCustomizers = taskSchedulerCustomizers; |
||||
} |
||||
|
||||
/** |
||||
* Set the maximum allowed number of threads. |
||||
* @param poolSize the pool size to set |
||||
* @return a new builder instance |
||||
*/ |
||||
public TaskSchedulerBuilder poolSize(int poolSize) { |
||||
return new TaskSchedulerBuilder(poolSize, this.threadNamePrefix, |
||||
this.taskSchedulerCustomizers); |
||||
} |
||||
|
||||
/** |
||||
* Set the prefix to use for the names of newly created threads. |
||||
* @param threadNamePrefix the thread name prefix to set |
||||
* @return a new builder instance |
||||
*/ |
||||
public TaskSchedulerBuilder threadNamePrefix(String threadNamePrefix) { |
||||
return new TaskSchedulerBuilder(this.poolSize, threadNamePrefix, |
||||
this.taskSchedulerCustomizers); |
||||
} |
||||
|
||||
/** |
||||
* Set the {@link TaskSchedulerCustomizer TaskSchedulerCustomizers} that should be |
||||
* applied to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the |
||||
* order that they were added after builder configuration has been applied. Setting |
||||
* this value will replace any previously configured customizers. |
||||
* @param taskSchedulerCustomizers the customizers to set |
||||
* @return a new builder instance |
||||
* @see #additionalCustomizers(TaskSchedulerCustomizer...) |
||||
*/ |
||||
public TaskSchedulerBuilder customizers( |
||||
TaskSchedulerCustomizer... taskSchedulerCustomizers) { |
||||
Assert.notNull(taskSchedulerCustomizers, |
||||
"TaskSchedulerCustomizers must not be null"); |
||||
return customizers(Arrays.asList(taskSchedulerCustomizers)); |
||||
} |
||||
|
||||
/** |
||||
* Set the {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be |
||||
* applied to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the |
||||
* order that they were added after builder configuration has been applied. Setting |
||||
* this value will replace any previously configured customizers. |
||||
* @param taskSchedulerCustomizers the customizers to set |
||||
* @return a new builder instance |
||||
* @see #additionalCustomizers(TaskSchedulerCustomizer...) |
||||
*/ |
||||
public TaskSchedulerBuilder customizers( |
||||
Collection<? extends TaskSchedulerCustomizer> taskSchedulerCustomizers) { |
||||
Assert.notNull(taskSchedulerCustomizers, |
||||
"TaskSchedulerCustomizers must not be null"); |
||||
return new TaskSchedulerBuilder(this.poolSize, this.threadNamePrefix, |
||||
Collections.unmodifiableSet(new LinkedHashSet<TaskSchedulerCustomizer>( |
||||
taskSchedulerCustomizers))); |
||||
} |
||||
|
||||
/** |
||||
* Add {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be applied |
||||
* to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the order that |
||||
* they were added after builder configuration has been applied. |
||||
* @param taskSchedulerCustomizers the customizers to add |
||||
* @return a new builder instance |
||||
* @see #customizers(TaskSchedulerCustomizer...) |
||||
*/ |
||||
public TaskSchedulerBuilder additionalCustomizers( |
||||
TaskSchedulerCustomizer... taskSchedulerCustomizers) { |
||||
Assert.notNull(taskSchedulerCustomizers, |
||||
"TaskSchedulerCustomizers must not be null"); |
||||
return additionalCustomizers(Arrays.asList(taskSchedulerCustomizers)); |
||||
} |
||||
|
||||
/** |
||||
* Add {@link TaskSchedulerCustomizer taskSchedulerCustomizers} that should be applied |
||||
* to the {@link ThreadPoolTaskScheduler}. Customizers are applied in the order that |
||||
* they were added after builder configuration has been applied. |
||||
* @param taskSchedulerCustomizers the customizers to add |
||||
* @return a new builder instance |
||||
* @see #customizers(TaskSchedulerCustomizer...) |
||||
*/ |
||||
public TaskSchedulerBuilder additionalCustomizers( |
||||
Collection<? extends TaskSchedulerCustomizer> taskSchedulerCustomizers) { |
||||
Assert.notNull(taskSchedulerCustomizers, |
||||
"TaskSchedulerCustomizers must not be null"); |
||||
return new TaskSchedulerBuilder(this.poolSize, this.threadNamePrefix, |
||||
append(this.taskSchedulerCustomizers, taskSchedulerCustomizers)); |
||||
} |
||||
|
||||
/** |
||||
* Build a new {@link ThreadPoolTaskScheduler} instance and configure it using this |
||||
* builder. |
||||
* @return a configured {@link ThreadPoolTaskScheduler} instance. |
||||
* @see #configure(ThreadPoolTaskScheduler) |
||||
*/ |
||||
public ThreadPoolTaskScheduler build() { |
||||
return configure(new ThreadPoolTaskScheduler()); |
||||
} |
||||
|
||||
/** |
||||
* Configure the provided {@link ThreadPoolTaskScheduler} instance using this builder. |
||||
* @param <T> the type of task scheduler |
||||
* @param taskScheduler the {@link ThreadPoolTaskScheduler} to configure |
||||
* @return the task scheduler instance |
||||
* @see #build() |
||||
*/ |
||||
public <T extends ThreadPoolTaskScheduler> T configure(T taskScheduler) { |
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); |
||||
map.from(() -> this.poolSize).to(taskScheduler::setPoolSize); |
||||
map.from(() -> this.threadNamePrefix).to(taskScheduler::setThreadNamePrefix); |
||||
|
||||
if (!CollectionUtils.isEmpty(this.taskSchedulerCustomizers)) { |
||||
for (TaskSchedulerCustomizer customizer : this.taskSchedulerCustomizers) { |
||||
customizer.customize(taskScheduler); |
||||
} |
||||
} |
||||
return taskScheduler; |
||||
} |
||||
|
||||
private static <T> Set<T> append(Set<T> set, Collection<? extends T> additions) { |
||||
Set<T> result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet()); |
||||
result.addAll(additions); |
||||
return Collections.unmodifiableSet(result); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
/* |
||||
* Copyright 2012-2018 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 |
||||
* |
||||
* http://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.task; |
||||
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
||||
|
||||
/** |
||||
* Callback interface that can be used to customize a {@link ThreadPoolTaskScheduler}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 2.1.0 |
||||
*/ |
||||
@FunctionalInterface |
||||
public interface TaskSchedulerCustomizer { |
||||
|
||||
/** |
||||
* Callback to customize a {@link ThreadPoolTaskScheduler} instance. |
||||
* @param taskScheduler the task scheduler to customize |
||||
*/ |
||||
void customize(ThreadPoolTaskScheduler taskScheduler); |
||||
|
||||
} |
||||
@ -0,0 +1,128 @@
@@ -0,0 +1,128 @@
|
||||
/* |
||||
* Copyright 2012-2018 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 |
||||
* |
||||
* http://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.task; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.Set; |
||||
|
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.ExpectedException; |
||||
import org.mockito.Mockito; |
||||
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link TaskSchedulerBuilder}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
public class TaskSchedulerBuilderTests { |
||||
|
||||
@Rule |
||||
public ExpectedException thrown = ExpectedException.none(); |
||||
|
||||
private TaskSchedulerBuilder builder = new TaskSchedulerBuilder(); |
||||
|
||||
@Test |
||||
public void createWhenCustomizersAreNullShouldThrowException() { |
||||
this.thrown.expect(IllegalArgumentException.class); |
||||
this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); |
||||
new TaskSchedulerBuilder((TaskSchedulerCustomizer[]) null); |
||||
} |
||||
|
||||
@Test |
||||
public void poolSettingsShouldApply() { |
||||
ThreadPoolTaskScheduler scheduler = this.builder.poolSize(4).build(); |
||||
assertThat(scheduler.getPoolSize()).isEqualTo(4); |
||||
} |
||||
|
||||
@Test |
||||
public void threadNamePrefixShouldApply() { |
||||
ThreadPoolTaskScheduler executor = this.builder.threadNamePrefix("test-").build(); |
||||
assertThat(executor.getThreadNamePrefix()).isEqualTo("test-"); |
||||
} |
||||
|
||||
@Test |
||||
public void customizersWhenCustomizersAreNullShouldThrowException() { |
||||
this.thrown.expect(IllegalArgumentException.class); |
||||
this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); |
||||
this.builder.customizers((TaskSchedulerCustomizer[]) null); |
||||
} |
||||
|
||||
@Test |
||||
public void customizersCollectionWhenCustomizersAreNullShouldThrowException() { |
||||
this.thrown.expect(IllegalArgumentException.class); |
||||
this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); |
||||
this.builder.customizers((Set<TaskSchedulerCustomizer>) null); |
||||
} |
||||
|
||||
@Test |
||||
public void customizersShouldApply() { |
||||
TaskSchedulerCustomizer customizer = Mockito.mock(TaskSchedulerCustomizer.class); |
||||
ThreadPoolTaskScheduler executor = this.builder.customizers(customizer).build(); |
||||
Mockito.verify(customizer).customize(executor); |
||||
} |
||||
|
||||
@Test |
||||
public void customizersShouldBeAppliedLast() { |
||||
ThreadPoolTaskScheduler scheduler = Mockito.spy(new ThreadPoolTaskScheduler()); |
||||
this.builder.poolSize(4).threadNamePrefix("test-") |
||||
.additionalCustomizers((taskScheduler) -> { |
||||
Mockito.verify(taskScheduler).setPoolSize(4); |
||||
Mockito.verify(taskScheduler).setThreadNamePrefix("test-"); |
||||
}); |
||||
this.builder.configure(scheduler); |
||||
} |
||||
|
||||
@Test |
||||
public void customizersShouldReplaceExisting() { |
||||
TaskSchedulerCustomizer customizer1 = Mockito.mock(TaskSchedulerCustomizer.class); |
||||
TaskSchedulerCustomizer customizer2 = Mockito.mock(TaskSchedulerCustomizer.class); |
||||
ThreadPoolTaskScheduler executor = this.builder.customizers(customizer1) |
||||
.customizers(Collections.singleton(customizer2)).build(); |
||||
Mockito.verifyZeroInteractions(customizer1); |
||||
Mockito.verify(customizer2).customize(executor); |
||||
} |
||||
|
||||
@Test |
||||
public void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { |
||||
this.thrown.expect(IllegalArgumentException.class); |
||||
this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); |
||||
this.builder.additionalCustomizers((TaskSchedulerCustomizer[]) null); |
||||
} |
||||
|
||||
@Test |
||||
public void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { |
||||
this.thrown.expect(IllegalArgumentException.class); |
||||
this.thrown.expectMessage("TaskSchedulerCustomizers must not be null"); |
||||
this.builder.additionalCustomizers((Set<TaskSchedulerCustomizer>) null); |
||||
} |
||||
|
||||
@Test |
||||
public void additionalCustomizersShouldAddToExisting() { |
||||
TaskSchedulerCustomizer customizer1 = Mockito.mock(TaskSchedulerCustomizer.class); |
||||
TaskSchedulerCustomizer customizer2 = Mockito.mock(TaskSchedulerCustomizer.class); |
||||
ThreadPoolTaskScheduler scheduler = this.builder.customizers(customizer1) |
||||
.additionalCustomizers(customizer2).build(); |
||||
Mockito.verify(customizer1).customize(scheduler); |
||||
Mockito.verify(customizer2).customize(scheduler); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue