From d8ecdce83d732bfbbc61ede7bc4aa0f15bce9923 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 11 Aug 2017 16:26:46 -0400 Subject: [PATCH] INT-4326: Add endpoints.noAutoStartup property JIRA: https://jira.spring.io/browse/INT-4326 To let to disable autoStartup for particular endpoint bean globally, in one place, add `spring.integration.endpoints.noAutoStartup` to the `spring.integration.properties` So, now all the `AbstractEndpoint` checks that property for matching its bean name to configure `autoStartup` property to `false` **Cherry-pick to 4.3.x** Conflicts: spring-integration-core/src/main/resources/META-INF/spring.integration.default.properties spring-integration-core/src/test/resources/META-INF/spring.integration.properties src/reference/asciidoc/configuration.adoc Resolved. --- .../config/ConsumerEndpointFactoryBean.java | 12 ++++++--- .../context/IntegrationProperties.java | 8 +++++- .../endpoint/AbstractEndpoint.java | 25 ++++++++++++++++++- .../spring.integration.default.properties | 1 + .../IntegrationContextTests-context.xml | 3 +++ .../context/IntegrationContextTests.java | 16 ++++++++++-- .../META-INF/spring.integration.properties | 1 + src/reference/asciidoc/configuration.adoc | 10 ++++++++ 8 files changed, 68 insertions(+), 8 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/ConsumerEndpointFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/config/ConsumerEndpointFactoryBean.java index 96bd24ca1a..041e36247e 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/ConsumerEndpointFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/ConsumerEndpointFactoryBean.java @@ -71,7 +71,7 @@ public class ConsumerEndpointFactoryBean private volatile PollerMetadata pollerMetadata; - private volatile boolean autoStartup = true; + private volatile Boolean autoStartup; private volatile int phase = 0; @@ -133,7 +133,7 @@ public class ConsumerEndpointFactoryBean this.beanClassLoader = classLoader; } - public void setAutoStartup(boolean autoStartup) { + public void setAutoStartup(Boolean autoStartup) { this.autoStartup = autoStartup; } @@ -257,7 +257,9 @@ public class ConsumerEndpointFactoryBean Assert.isNull(this.pollerMetadata, "A poller should not be specified for endpoint '" + this.beanName + "', since '" + channel + "' is a SubscribableChannel (not pollable)."); this.endpoint = new EventDrivenConsumer((SubscribableChannel) channel, this.handler); - if (this.logger.isWarnEnabled() && !this.autoStartup && channel instanceof FixedSubscriberChannel) { + if (this.logger.isWarnEnabled() + && Boolean.FALSE.equals(this.autoStartup) + && channel instanceof FixedSubscriberChannel) { this.logger.warn("'autoStartup=\"false\"' has no effect when using a FixedSubscriberChannel"); } } @@ -287,7 +289,9 @@ public class ConsumerEndpointFactoryBean } this.endpoint.setBeanName(this.beanName); this.endpoint.setBeanFactory(this.beanFactory); - this.endpoint.setAutoStartup(this.autoStartup); + if (this.autoStartup != null) { + this.endpoint.setAutoStartup(this.autoStartup); + } int phase = this.phase; if (!this.isPhaseSet && this.endpoint instanceof PollingConsumer) { phase = Integer.MAX_VALUE / 2; 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 ebb1611d17..383dc40032 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 @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * Copyright 2014-2017 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. @@ -29,6 +29,7 @@ import org.springframework.core.io.support.ResourcePatternResolver; * their default values from resources 'META-INF/spring.integration.default.properties'. * * @author Artem Bilan + * * @since 3.0 */ public final class IntegrationProperties { @@ -81,6 +82,11 @@ public final class IntegrationProperties { */ public static final String READ_ONLY_HEADERS = INTEGRATION_PROPERTIES_PREFIX + "readOnly.headers"; + /** + * Specifies the value of {@link org.springframework.integration.endpoint.AbstractEndpoint#autoStartup}. + */ + public static final String ENDPOINTS_NO_AUTO_STARTUP = INTEGRATION_PROPERTIES_PREFIX + "endpoints.noAutoStartup"; + private static Properties defaults; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractEndpoint.java b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractEndpoint.java index 7c3e0fdbad..a455495b55 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractEndpoint.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2017 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. @@ -21,7 +21,9 @@ import java.util.concurrent.locks.ReentrantLock; import org.springframework.context.SmartLifecycle; import org.springframework.integration.context.IntegrationObjectSupport; +import org.springframework.integration.context.IntegrationProperties; import org.springframework.scheduling.TaskScheduler; +import org.springframework.util.PatternMatchUtils; /** * The base class for Message Endpoint implementations. @@ -36,9 +38,12 @@ import org.springframework.scheduling.TaskScheduler; * @author Mark Fisher * @author Kris Jacyna * @author Gary Russell + * @author Artem Bilan */ public abstract class AbstractEndpoint extends IntegrationObjectSupport implements SmartLifecycle { + private boolean autoStartupSetExplicitly; + private volatile boolean autoStartup = true; private volatile int phase = 0; @@ -52,6 +57,7 @@ public abstract class AbstractEndpoint extends IntegrationObjectSupport implemen public void setAutoStartup(boolean autoStartup) { this.autoStartup = autoStartup; + this.autoStartupSetExplicitly = true; } public void setPhase(int phase) { @@ -63,6 +69,23 @@ public abstract class AbstractEndpoint extends IntegrationObjectSupport implemen super.setTaskScheduler(taskScheduler); } + @Override + protected void onInit() throws Exception { + super.onInit(); + + if (!this.autoStartupSetExplicitly) { + String[] endpointNamePatterns = + getIntegrationProperty(IntegrationProperties.ENDPOINTS_NO_AUTO_STARTUP, String[].class); + + for (String pattern : endpointNamePatterns) { + if (PatternMatchUtils.simpleMatch(pattern, getComponentName())) { + this.autoStartup = false; + break; + } + } + } + } + // SmartLifecycle implementation @Override 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 0b04709a74..5ad42a3a9b 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 @@ -7,3 +7,4 @@ spring.integration.messagingAnnotations.require.componentAnnotation=false spring.integration.messagingGateway.convertReceiveMessage=false # Defaults to MessageHeaders.ID and MessageHeaders.TIMESTAMP spring.integration.readOnly.headers= +spring.integration.endpoints.noAutoStartup= diff --git a/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests-context.xml index 4bbd23523b..cec135faa7 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/context/IntegrationContextTests-context.xml @@ -11,4 +11,7 @@ + + 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 61965697b7..718e5c88a5 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2017 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. @@ -17,6 +17,8 @@ package org.springframework.integration.context; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import java.util.Properties; @@ -25,6 +27,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.integration.endpoint.AbstractEndpoint; import org.springframework.integration.test.util.TestUtils; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.test.context.ContextConfiguration; @@ -32,6 +35,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Artem Bilan + * * @since 3.0 */ @ContextConfiguration @@ -44,7 +48,11 @@ public class IntegrationContextTests { @Autowired @Qualifier("fooService") - private IntegrationObjectSupport serviceActivator; + private AbstractEndpoint serviceActivator; + + @Autowired + @Qualifier("fooServiceExplicit") + private AbstractEndpoint serviceActivatorExplicit; @Autowired private ThreadPoolTaskScheduler taskScheduler; @@ -55,6 +63,10 @@ public class IntegrationContextTests { assertEquals("20", this.integrationProperties.get(IntegrationProperties.TASK_SCHEDULER_POOL_SIZE)); assertEquals(this.integrationProperties, this.serviceActivator.getIntegrationProperties()); assertEquals(20, TestUtils.getPropertyValue(this.taskScheduler, "poolSize")); + assertFalse(this.serviceActivator.isAutoStartup()); + assertFalse(this.serviceActivator.isRunning()); + assertTrue(this.serviceActivatorExplicit.isAutoStartup()); + assertTrue(this.serviceActivatorExplicit.isRunning()); } } diff --git a/spring-integration-core/src/test/resources/META-INF/spring.integration.properties b/spring-integration-core/src/test/resources/META-INF/spring.integration.properties index bda849fe9e..1affb77801 100644 --- a/spring-integration-core/src/test/resources/META-INF/spring.integration.properties +++ b/spring-integration-core/src/test/resources/META-INF/spring.integration.properties @@ -4,3 +4,4 @@ spring.integration.taskScheduler.poolSize=20 spring.integration.messagingTemplate.throwExceptionOnLateReply=true spring.integration.readOnly.headers=contentType +spring.integration.endpoints.noAutoStartup=fooService* diff --git a/src/reference/asciidoc/configuration.adoc b/src/reference/asciidoc/configuration.adoc index 3e0cc5f7a2..572b643f31 100644 --- a/src/reference/asciidoc/configuration.adoc +++ b/src/reference/asciidoc/configuration.adoc @@ -206,6 +206,8 @@ spring.integration.channels.maxBroadcastSubscribers=0x7fffffff <3> spring.integration.taskScheduler.poolSize=10 <4> spring.integration.messagingTemplate.throwExceptionOnLateReply=false <5> spring.integration.messagingAnnotations.require.componentAnnotation=false <6> +spring.integration.readOnly.headers= <7> +spring.integration.endpoints.noAutoStartup= <8> ---- <1> When true, `input-channel` s will be automatically declared as `DirectChannel` s when not explicitly found in the @@ -226,6 +228,14 @@ expecting a reply - because the sending thread has timed out, or already receive <6> When `true`, Messaging Annotation Support (<>) requires a declaration of the `@MessageEndpoint` (or any other `@Component`) annotation on the class level. +<7> A comma-separated list of message header names which should not be populated into `Message` s during a header copying operation. +The list is used by the `DefaultMessageBuilderFactory` bean and propagated to the `IntegrationMessageHeaderAccessor` instances (see <>), used to build messages via `MessageBuilder` (see <>). +By default only `MessageHeaders.ID` and `MessageHeaders.TIMESTAMP` are not copied during message building. +_Since version 4.3.2_ +<8> A comma-separated list of `AbstractEndpoint` bean names patterns (`xxx*`, `*xxx`, `*xxx*` or `xxx*yyy`) which should not be started automatically during application startup. +These endpoints can be started later manually by their bean name via `Control Bus` (see <>), by their role using the `SmartLifecycleRoleController` (see <>) or via simple `Lifecycle` bean injection. +The effect of this global property can be explicitly overridden by specifying `auto-startup` XML or `autoStartup` annotation attribute, or via call to the `AbstractEndpoint.setAutoStartup()` in bean definition. +_Since version 4.3.12_ These properties can be overridden by adding a file `/META-INF/spring.integration.properties` to the classpath. It is not necessary to provide all the properties, just those that you want to override.