diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java index 04de88bf08..c0ef5e18cb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -34,7 +34,9 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration; +import org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.task.TaskSchedulerBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @@ -44,6 +46,7 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.integration.config.EnableIntegration; import org.springframework.integration.config.EnableIntegrationManagement; import org.springframework.integration.config.IntegrationManagementConfigurer; +import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.gateway.GatewayProxyFactoryBean; import org.springframework.integration.jdbc.store.JdbcMessageStore; import org.springframework.integration.jmx.config.EnableIntegrationMBeanExport; @@ -56,6 +59,7 @@ import org.springframework.integration.rsocket.outbound.RSocketOutboundGateway; import org.springframework.messaging.rsocket.RSocketRequester; import org.springframework.messaging.rsocket.RSocketStrategies; import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.util.StringUtils; /** @@ -72,7 +76,8 @@ import org.springframework.util.StringUtils; @Configuration(proxyBeanMethods = false) @ConditionalOnClass(EnableIntegration.class) @EnableConfigurationProperties(IntegrationProperties.class) -@AutoConfigureAfter({ DataSourceAutoConfiguration.class, JmxAutoConfiguration.class }) +@AutoConfigureAfter({ DataSourceAutoConfiguration.class, JmxAutoConfiguration.class, + TaskSchedulingAutoConfiguration.class }) public class IntegrationAutoConfiguration { /** @@ -84,6 +89,22 @@ public class IntegrationAutoConfiguration { } + /** + * Expose a standard {@link ThreadPoolTaskScheduler} if the user has not enabled task + * scheduling explicitly. + */ + @Configuration(proxyBeanMethods = false) + @ConditionalOnBean(TaskSchedulerBuilder.class) + @ConditionalOnMissingBean(name = IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME) + protected static class IntegrationTaskSchedulerConfiguration { + + @Bean(name = IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME) + public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) { + return builder.build(); + } + + } + /** * Spring Integration JMX configuration. */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java index 0a3bd0dfe7..a6b9c0eaa7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/integration/IntegrationAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -34,6 +34,7 @@ import org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfig import org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration; import org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration; import org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration; +import org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration; import org.springframework.boot.jdbc.DataSourceInitializationMode; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -42,6 +43,7 @@ import org.springframework.context.annotation.Primary; import org.springframework.integration.annotation.IntegrationComponentScan; import org.springframework.integration.annotation.MessagingGateway; import org.springframework.integration.config.IntegrationManagementConfigurer; +import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.core.MessageSource; import org.springframework.integration.endpoint.MessageProcessorMessageSource; import org.springframework.integration.gateway.RequestReplyExchanger; @@ -56,6 +58,7 @@ import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jmx.export.MBeanExporter; import org.springframework.messaging.Message; import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler; +import org.springframework.scheduling.TaskScheduler; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -221,6 +224,32 @@ class IntegrationAutoConfigurationTests { }); } + @Test + void taskSchedulerIsNotOverridden() { + this.contextRunner.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class)) + .withPropertyValues("spring.task.scheduling.thread-name-prefix=integration-scheduling-", + "spring.task.scheduling.pool.size=3") + .run((context) -> { + assertThat(context).hasSingleBean(TaskScheduler.class); + assertThat(context).getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class) + .hasFieldOrPropertyWithValue("threadNamePrefix", "integration-scheduling-") + .hasFieldOrPropertyWithValue("scheduledExecutor.corePoolSize", 3); + }); + } + + @Test + void taskSchedulerCanBeCustomized() { + TaskScheduler customTaskScheduler = mock(TaskScheduler.class); + this.contextRunner.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class)) + .withBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class, + () -> customTaskScheduler) + .run((context) -> { + assertThat(context).hasSingleBean(TaskScheduler.class); + assertThat(context).getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME) + .isSameAs(customTaskScheduler); + }); + } + @Configuration(proxyBeanMethods = false) static class CustomMBeanExporter { diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index 2267be91bc..7398be08b7 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -6249,7 +6249,7 @@ The auto-configured `TaskExecutorBuilder` allows you to easily create instances ==== 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: [source,yaml,indent=0,configprops,configblocks] ---- @@ -6265,8 +6265,18 @@ Those default settings can be fine-tuned using the `spring.task.execution` names This changes the thread pool to use a bounded queue so that when the queue is full (100 tasks), the thread pool increases to maximum 16 threads. Shrinking of the pool is more aggressive as threads are reclaimed when they are idle for 10 seconds (rather than 60 seconds by default). -A `ThreadPoolTaskScheduler` can also be auto-configured if need to be associated to scheduled task execution (`@EnableScheduling`). -The thread pool uses one thread by default and those settings can be fine-tuned using the `spring.task.scheduling` namespace. +A `ThreadPoolTaskScheduler` can also be auto-configured if need to be associated to scheduled task execution (e.g. `@EnableScheduling`). +The thread pool uses one thread by default and its settings can be fine-tuned using the `spring.task.scheduling` namespace, as shown in the following example: + +[source,yaml,indent=0,configprops,configblocks] +---- + spring: + task: + scheduling: + thread-name-prefix: "scheduling-" + pool: + size: 2 +---- Both a `TaskExecutorBuilder` bean and a `TaskSchedulerBuilder` bean are made available in the context if a custom executor or scheduler needs to be created. @@ -6278,6 +6288,8 @@ Spring Boot offers several conveniences for working with {spring-integration}[Sp Spring Integration provides abstractions over messaging and also other transports such as HTTP, TCP, and others. If Spring Integration is available on your classpath, it is initialized through the `@EnableIntegration` annotation. +Spring Integration polling logic relies <>. + Spring Boot also configures some features that are triggered by the presence of additional Spring Integration modules. If `spring-integration-jmx` is also on the classpath, message processing statistics are published over JMX. If `spring-integration-jdbc` is available, the default database schema can be created on startup, as shown in the following line: