diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java index dbe3e0c911..136034b038 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java @@ -44,7 +44,6 @@ import org.springframework.integration.channel.PublishSubscribeChannel; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.context.IntegrationProperties; -import org.springframework.integration.endpoint.management.IntegrationKeepAlive; import org.springframework.integration.handler.LoggingHandler; import org.springframework.integration.handler.support.IntegrationMessageHandlerMethodFactory; import org.springframework.integration.json.JsonPathUtils; @@ -130,7 +129,6 @@ public class DefaultConfiguringBeanFactoryPostProcessor implements BeanDefinitio registerListMessageHandlerMethodFactory(); registerIntegrationConfigurationReport(); registerControlBusCommandRegistry(); - registerKeepAlive(); } @Override @@ -462,15 +460,4 @@ public class DefaultConfiguringBeanFactoryPostProcessor implements BeanDefinitio IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME); } - private void registerKeepAlive() { - if (!this.beanFactory.containsBean(IntegrationContextUtils.INTEGRATION_KEEP_ALIVE_BEAN_NAME)) { - BeanDefinitionBuilder builder = - BeanDefinitionBuilder.genericBeanDefinition(IntegrationKeepAlive.class) - .setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - - this.registry.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_KEEP_ALIVE_BEAN_NAME, - builder.getBeanDefinition()); - } - } - } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java index b404c06032..f7d2f8a857 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java @@ -100,18 +100,8 @@ public abstract class IntegrationContextUtils { public static final String LIST_MESSAGE_HANDLER_FACTORY_BEAN_NAME = "integrationListMessageHandlerMethodFactory"; - /** - * The bean name for the {@code org.springframework.integration.support.management.ControlBusCommandRegistry}. - * @since 6.4 - */ public static final String CONTROL_BUS_COMMAND_REGISTRY_BEAN_NAME = "controlBusCommandRegistry"; - /** - * The bean name for the {@code org.springframework.integration.endpoint.management.IntegrationKeepAlive}. - * @since 6.4 - */ - public static final String INTEGRATION_KEEP_ALIVE_BEAN_NAME = "integrationKeepAlive"; - /** * The default timeout for blocking operations like send and receive messages. * @since 6.1 diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java index 41c58b376e..d31bd8c930 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java @@ -25,7 +25,7 @@ import org.springframework.util.StringUtils; /** * Utility class to encapsulate infrastructure Integration properties constants and their default values. - * The default values can be overridden by the {@code META-INF/spring.integration.properties} with these entries + * The default values can be overridden by the {@code META-INF/spring.integration.properties} with this entries * (includes their default values): *
- * A bean for this class is registered automatically by Spring Integration infrastructure. - * It is started by application context for a blocked keep-alive dedicated thread - * only if there is no {@link AbstractPollingEndpoint} beans in the application context - * or {@link TaskScheduler} is configured for daemon (or virtual) threads. - *
- * Can be stopped (or started respectively) manually after injection into some target service if found redundant. - *
- * The {@link IntegrationProperties#KEEP_ALIVE} integration global - * property can be set to {@code false} to disable this component regardless of the application logic. - * - * @author Artem Bilan - * - * @since 6.4 - */ -public class IntegrationKeepAlive implements SmartLifecycle, SmartInitializingSingleton, BeanFactoryAware { - - private static final Log LOG = LogFactory.getLog(IntegrationKeepAlive.class); - - private final AtomicBoolean running = new AtomicBoolean(); - - private BeanFactory beanFactory; - - private boolean autoStartup; - - private volatile Thread keepAliveThread; - - @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; - } - - @Override - public void afterSingletonsInstantiated() { - IntegrationProperties integrationProperties = IntegrationContextUtils.getIntegrationProperties(this.beanFactory); - this.autoStartup = - integrationProperties.isKeepAlive() - && (isTaskSchedulerDaemon() || !isAbstractPollingEndpointPresent()); - } - - private boolean isTaskSchedulerDaemon() { - TaskScheduler taskScheduler = IntegrationContextUtils.getTaskScheduler(this.beanFactory); - AtomicBoolean isDaemon = new AtomicBoolean(); - CountDownLatch checkDaemonThreadLatch = new CountDownLatch(1); - taskScheduler.schedule(() -> { - isDaemon.set(Thread.currentThread().isDaemon()); - checkDaemonThreadLatch.countDown(); - }, Instant.now()); - - boolean logWarning = false; - try { - if (!checkDaemonThreadLatch.await(10, TimeUnit.SECONDS)) { - logWarning = true; - } - } - catch (InterruptedException ex) { - logWarning = true; - } - if (logWarning) { - LOG.warn("The 'IntegrationKeepAlive' cannot check a 'TaskScheduler' daemon threads status. " + - "Falling back to 'keep-alive'"); - } - return isDaemon.get(); - } - - private boolean isAbstractPollingEndpointPresent() { - return this.beanFactory.getBeanProvider(AbstractPollingEndpoint.class) - .stream() - .findAny() - .isPresent(); - } - - @Override - public boolean isAutoStartup() { - return this.autoStartup; - } - - @Override - public void start() { - if (this.running.compareAndSet(false, true)) { - this.keepAliveThread = - new Thread(() -> { - while (true) { - try { - Thread.sleep(Long.MAX_VALUE); - } - catch (InterruptedException ex) { - break; - } - } - }); - this.keepAliveThread.setDaemon(false); - this.keepAliveThread.setName("spring-integration-keep-alive"); - this.keepAliveThread.start(); - } - } - - @Override - public void stop() { - if (this.running.compareAndSet(true, false)) { - this.keepAliveThread.interrupt(); - } - } - - @Override - public boolean isRunning() { - return this.running.get(); - } - -} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/management/package-info.java b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/management/package-info.java index d92f03293e..694a540175 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/management/package-info.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/management/package-info.java @@ -1,6 +1,4 @@ /** * Provides classes related to endpoint management. */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields package org.springframework.integration.endpoint.management; diff --git a/spring-integration-core/src/main/resources/META-INF/spring.integration.default.properties b/spring-integration-core/src/main/resources/META-INF/spring.integration.default.properties index 7534067d51..573f1916e6 100644 --- a/spring-integration-core/src/main/resources/META-INF/spring.integration.default.properties +++ b/spring-integration-core/src/main/resources/META-INF/spring.integration.default.properties @@ -9,4 +9,3 @@ spring.integration.messagingTemplate.throwExceptionOnLateReply=false spring.integration.readOnly.headers= spring.integration.endpoints.noAutoStartup= spring.integration.endpoints.defaultTimeout=30000 -spring.integration.keepAlive=true diff --git a/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests.java b/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests.java index 74ea143e26..46aab1d344 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests.java @@ -21,7 +21,6 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.integration.endpoint.AbstractEndpoint; -import org.springframework.integration.endpoint.management.IntegrationKeepAlive; import org.springframework.integration.test.util.TestUtils; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.test.annotation.DirtiesContext; @@ -53,9 +52,6 @@ public class IntegrationContextTests { @Autowired private ThreadPoolTaskScheduler taskScheduler; - @Autowired - private IntegrationKeepAlive integrationKeepAlive; - @Test public void testIntegrationContextComponents() { assertThat(this.integrationProperties.isMessagingTemplateThrowExceptionOnLateReply()).isTrue(); @@ -66,7 +62,6 @@ public class IntegrationContextTests { assertThat(this.serviceActivator.isRunning()).isFalse(); assertThat(this.serviceActivatorExplicit.isAutoStartup()).isTrue(); assertThat(this.serviceActivatorExplicit.isRunning()).isTrue(); - assertThat(this.integrationKeepAlive.isRunning()).isTrue(); } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/endpoint/IntegrationKeepAliveTests.java b/spring-integration-core/src/test/java/org/springframework/integration/endpoint/IntegrationKeepAliveTests.java deleted file mode 100644 index f6b19c0438..0000000000 --- a/spring-integration-core/src/test/java/org/springframework/integration/endpoint/IntegrationKeepAliveTests.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2024 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 - * - * https://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.integration.endpoint; - -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.integration.config.EnableIntegration; -import org.springframework.integration.context.IntegrationContextUtils; -import org.springframework.integration.context.IntegrationProperties; -import org.springframework.integration.endpoint.management.IntegrationKeepAlive; -import org.springframework.integration.test.util.TestUtils; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; -import static org.mockito.Mockito.mock; - -/** - * @author Artem Bilan - * - * @since 6.4 - */ -@SpringJUnitConfig -@DirtiesContext -public class IntegrationKeepAliveTests { - - @Test - void keepAliveIsActive(@Autowired IntegrationKeepAlive integrationKeepAlive) { - assertThat(integrationKeepAlive.isRunning()).isTrue(); - Thread keepAliveThread = TestUtils.getPropertyValue(integrationKeepAlive, "keepAliveThread", Thread.class); - assertThat(keepAliveThread.isAlive()).isTrue(); - integrationKeepAlive.stop(); - await().untilAsserted(() -> assertThat(keepAliveThread.isAlive()).isFalse()); - integrationKeepAlive.start(); - } - - @Configuration - @EnableIntegration - public static class TestConfiguration { - - } - - @Nested - @ContextConfiguration(classes = WithPollingEndpoint.WithPollingEndpointConfig.class) - class WithPollingEndpoint { - - @Test - void keepAliveNotActive(@Autowired IntegrationKeepAlive integrationKeepAlive) { - assertThat(integrationKeepAlive.isRunning()).isFalse(); - } - - @Configuration - static class WithPollingEndpointConfig { - - @Bean - AbstractPollingEndpoint mockPollingEndpoint() { - return mock(); - } - - } - - } - - @Nested - @ContextConfiguration(classes = WithDaemonTaskScheduler.WithDaemonTaskSchedulerConfig.class) - class WithDaemonTaskScheduler { - - @Test - void keepAliveActive(@Autowired IntegrationKeepAlive integrationKeepAlive) { - assertThat(integrationKeepAlive.isRunning()).isTrue(); - } - - @Configuration - static class WithDaemonTaskSchedulerConfig { - - @Bean - AbstractPollingEndpoint mockPollingEndpoint() { - return mock(); - } - - @Bean - String daemonSetter(ThreadPoolTaskScheduler taskScheduler) { - taskScheduler.setDaemon(true); - return null; - } - - } - - } - - @Nested - @ContextConfiguration(classes = WithGlobalProperty.WithGlobalPropertyConfig.class) - class WithGlobalProperty { - - @Test - void keepAliveNotActive(@Autowired IntegrationKeepAlive integrationKeepAlive) { - assertThat(integrationKeepAlive.isRunning()).isFalse(); - } - - @Configuration - static class WithGlobalPropertyConfig { - - @Bean(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME) - static IntegrationProperties integrationProperties() { - IntegrationProperties integrationProperties = new IntegrationProperties(); - integrationProperties.setKeepAlive(false); - return integrationProperties; - } - - } - - } - -} diff --git a/src/reference/antora/modules/ROOT/nav.adoc b/src/reference/antora/modules/ROOT/nav.adoc index 16fde26c3d..61e2b1e327 100644 --- a/src/reference/antora/modules/ROOT/nav.adoc +++ b/src/reference/antora/modules/ROOT/nav.adoc @@ -99,7 +99,6 @@ ** xref:shutdown.adoc[] ** xref:graph.adoc[] ** xref:integration-graph-controller.adoc[] -** xref:keep-alive.adoc[] * xref:reactive-streams.adoc[] * xref:native-aot.adoc[] * xref:endpoint-summary.adoc[] diff --git a/src/reference/antora/modules/ROOT/pages/configuration/global-properties.adoc b/src/reference/antora/modules/ROOT/pages/configuration/global-properties.adoc index adb62534ef..e631b390f2 100644 --- a/src/reference/antora/modules/ROOT/pages/configuration/global-properties.adoc +++ b/src/reference/antora/modules/ROOT/pages/configuration/global-properties.adoc @@ -19,7 +19,6 @@ spring.integration.endpoints.noAutoStartup= <7> spring.integration.channels.error.requireSubscribers=true <8> spring.integration.channels.error.ignoreFailures=true <9> spring.integration.endpoints.defaultTimeout=30000 <10> -spring.integration.keepAlive=true <11> ---- <1> When true, `input-channel` instances are automatically declared as `DirectChannel` instances when not explicitly found in the application context. @@ -58,11 +57,6 @@ Since version 5.5. Default value is 30 seconds to avoid indefinite blocking. Can be configured to a negative value to restore infinite blocking behavior in endpoints. Since version 6.2. - -<11> Whether to start the `IntegrationKeepAlive`. -Default is `true`, however depends on the beans in the application context. -See xref:keep-alive.adoc[Keep Alive] for more information. -Since version 6.4. ==== These properties can be overridden by adding a `/META-INF/spring.integration.properties` file to the classpath or an `IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME` bean for the `org.springframework.integration.context.IntegrationProperties` instance. @@ -83,6 +77,5 @@ spring.integration.channels.maxBroadcastSubscribers=0x7fffffff spring.integration.readOnly.headers= spring.integration.messagingTemplate.throwExceptionOnLateReply=true spring.integration.endpoints.defaultTimeout=30000 -spring.integration.keepAlive=false ---- diff --git a/src/reference/antora/modules/ROOT/pages/keep-alive.adoc b/src/reference/antora/modules/ROOT/pages/keep-alive.adoc deleted file mode 100644 index 623a47b5c1..0000000000 --- a/src/reference/antora/modules/ROOT/pages/keep-alive.adoc +++ /dev/null @@ -1,17 +0,0 @@ -[[keep-alive]] -= Integration Keep Alive - -Starting with version 6.4, Spring Integration provides an `IntegrationKeepAlive` infrastructure bean. -It manages an `spring-integration-keep-alive` non-daemon forever thread which keeps an application running. -In some use-cases, e.g. `WebSocketInboundChannelAdapter` based on the `StandardWebSocketClient` does not use non-daemon thread for session, therefore an application may exit prematurely. -Or an application logic may have only service activators or outbound channel adapters which rely on some other interaction, but not loops from executors like the one from Web server. -Or all the threads in the application are virtual. - -The `IntegrationKeepAlive` is started automatically only if `TaskScheduler` is configured for non-daemon threads and there is no `AbstractPollingEndpoint` beans in the application context. -In case of the `TaskScheduler` bean configured for daemon or virtual threads, the `IntegrationKeepAlive` is started regardless of the presence for `AbstractPollingEndpoint` beans. - -This component can be disabled by the `spring.integration.keepAlive` global property. -See xref:configuration/global-properties.adoc[Global Properties] for more information. -The `IntegrationKeepAlive` can be injected in some service and stopped manually if there is no need to keep an application alive or such a status is managed somewhere else. - -See also Spring Boot https://docs.spring.io/spring-boot/reference/features/spring-application.html#features.spring-application.virtual-threads[Virtual Threads] documentation for a `spring.main.keep-alive` property. \ No newline at end of file diff --git a/src/reference/antora/modules/ROOT/pages/whats-new.adoc b/src/reference/antora/modules/ROOT/pages/whats-new.adoc index b1b669dec2..4187b3b7b9 100644 --- a/src/reference/antora/modules/ROOT/pages/whats-new.adoc +++ b/src/reference/antora/modules/ROOT/pages/whats-new.adoc @@ -27,10 +27,6 @@ The SpEL evaluation infrastructure now supports configuration for `IndexAccessor Also, an out-of-the-box `JsonIndexAccessor` is provided. See xref:spel.adoc[SpEL Support] for more information. -The `IntegrationKeepAlive` component has been introduced. -See xref:keep-alive.adoc[Integration Keep Alive] for more information. - - [[x6.4-general]] === General Changes