From d84392fa781ba4086f7bde1eaf41834bc8c92631 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Thu, 4 Feb 2021 13:09:29 -0500 Subject: [PATCH 1/3] Make Scheduler consistent for Spring Integration Related to https://stackoverflow.com/questions/65883496/mix-spring-integration-and-spring-scheduler Currently Spring Integration creates its own `TaskScheduler` bean if one doesn't exist in the ctx yet. When we add `@EnableScheduling`, Spring Boot auto-configures one for us, but this one comes with slightly different options then one in Spring Integration * Make Spring Integration auto-configuration to rely on the auto-configured `TaskScheduler`, so we will have a consistency when we use just Spring Integration or with `@Scheduled` methods and would rely on a single set of configuration properties for `TaskScheduler`. It does not make it consistent with what we have in Spring Integration by default, but Spring Boot may have its own opinion how to auto-configure target features --- .../IntegrationAutoConfiguration.java | 25 +++++++++++++++++-- .../IntegrationAutoConfigurationTests.java | 23 +++++++++++++++-- .../docs/asciidoc/spring-boot-features.adoc | 4 +++ 3 files changed, 48 insertions(+), 4 deletions(-) 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 04de88bf08a5..7effbdac5d16 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.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; @@ -56,6 +58,8 @@ import org.springframework.messaging.rsocket.RSocketRequester; import org.springframework.messaging.rsocket.RSocketStrategies; import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.util.StringUtils; /** @@ -72,9 +76,26 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(EnableIntegration.class) @EnableConfigurationProperties(IntegrationProperties.class) -@AutoConfigureAfter({ DataSourceAutoConfiguration.class, JmxAutoConfiguration.class }) +@AutoConfigureAfter({ + DataSourceAutoConfiguration.class, + JmxAutoConfiguration.class, + TaskSchedulingAutoConfiguration.class }) public class IntegrationAutoConfiguration { + /** + * The {@link TaskScheduler} configuration. + */ + @Configuration(proxyBeanMethods = false) + protected static class IntegrationTaskSchedulerConfiguration { + + @Bean + @ConditionalOnMissingBean + public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) { + return builder.build(); + } + + } + /** * Basic Spring Integration 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 0a3bd0dfe7ef..542bcf0ff6a7 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.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.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.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; @@ -71,7 +74,10 @@ class IntegrationAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, IntegrationAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of( + JmxAutoConfiguration.class, + IntegrationAutoConfiguration.class, + TaskSchedulingAutoConfiguration.class)); @Test void integrationIsAvailable() { @@ -221,6 +227,19 @@ void rsocketSupportEnabled() { }); } + @Test + void taskSchedulerAutoConfigured() { + this.contextRunner + .withPropertyValues("spring.task.scheduling.thread-name-prefix=integration-scheduling-", + "spring.task.scheduling.pool.size=3") + .run((context) -> + assertThat(context) + .getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class) + .hasFieldOrPropertyWithValue("threadNamePrefix", "integration-scheduling-") + .hasFieldOrPropertyWithValue("scheduledExecutor.corePoolSize", 3) + ); + } + @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 6123756b13b0..528842fe2365 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 @@ -6540,6 +6540,10 @@ 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 is based on the `TaskScheduler`. +So, it relies on the auto-configured one (see the previous section), or exposes a `taskScheduler` bean according provided `spring.task.scheduling` configuration properties. +If only Spring Integration is used, the `@EnableScheduling` annotation is optional and can be omitted on the target configuration classes. + 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: From ce94a69db001a7f765a2febde221e9f76d687fdd Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 8 Feb 2021 16:34:10 -0500 Subject: [PATCH 2/3] * Add `@ConditionalOnBean(TaskSchedulerBuilder.class)` to avoid situations when `TaskSchedulingAutoConfiguration` is excluded from the auto-configuration --- .../autoconfigure/integration/IntegrationAutoConfiguration.java | 1 + 1 file changed, 1 insertion(+) 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 7effbdac5d16..ee15e459461a 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 @@ -86,6 +86,7 @@ public class IntegrationAutoConfiguration { * The {@link TaskScheduler} configuration. */ @Configuration(proxyBeanMethods = false) + @ConditionalOnBean(TaskSchedulerBuilder.class) protected static class IntegrationTaskSchedulerConfiguration { @Bean From 74de834c30a6d46ee156e37e97b041efbca8b121 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 8 Feb 2021 18:39:39 -0500 Subject: [PATCH 3/3] * `gradlew format` --- .../integration/IntegrationAutoConfiguration.java | 4 +--- .../IntegrationAutoConfigurationTests.java | 14 +++++--------- 2 files changed, 6 insertions(+), 12 deletions(-) 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 ee15e459461a..5fa58d50e332 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 @@ -76,9 +76,7 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(EnableIntegration.class) @EnableConfigurationProperties(IntegrationProperties.class) -@AutoConfigureAfter({ - DataSourceAutoConfiguration.class, - JmxAutoConfiguration.class, +@AutoConfigureAfter({ DataSourceAutoConfiguration.class, JmxAutoConfiguration.class, TaskSchedulingAutoConfiguration.class }) public class IntegrationAutoConfiguration { 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 542bcf0ff6a7..0c30e71b3c83 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 @@ -74,9 +74,7 @@ class IntegrationAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of( - JmxAutoConfiguration.class, - IntegrationAutoConfiguration.class, + .withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, IntegrationAutoConfiguration.class, TaskSchedulingAutoConfiguration.class)); @Test @@ -232,12 +230,10 @@ void taskSchedulerAutoConfigured() { this.contextRunner .withPropertyValues("spring.task.scheduling.thread-name-prefix=integration-scheduling-", "spring.task.scheduling.pool.size=3") - .run((context) -> - assertThat(context) - .getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class) - .hasFieldOrPropertyWithValue("threadNamePrefix", "integration-scheduling-") - .hasFieldOrPropertyWithValue("scheduledExecutor.corePoolSize", 3) - ); + .run((context) -> assertThat(context) + .getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class) + .hasFieldOrPropertyWithValue("threadNamePrefix", "integration-scheduling-") + .hasFieldOrPropertyWithValue("scheduledExecutor.corePoolSize", 3)); } @Configuration(proxyBeanMethods = false)