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.
This commit is contained in:
Artem Bilan
2017-08-11 16:26:46 -04:00
committed by Gary Russell
parent c877b041d4
commit d8ecdce83d
8 changed files with 68 additions and 8 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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=

View File

@@ -11,4 +11,7 @@
<service-activator id="fooService" input-channel="foo" output-channel="nullChannel" expression="'foo'"/>
<service-activator id="fooServiceExplicit" input-channel="foo" output-channel="nullChannel" expression="'foo'"
auto-startup="true"/>
</beans:beans>

View File

@@ -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());
}
}

View File

@@ -4,3 +4,4 @@
spring.integration.taskScheduler.poolSize=20
spring.integration.messagingTemplate.throwExceptionOnLateReply=true
spring.integration.readOnly.headers=contentType
spring.integration.endpoints.noAutoStartup=fooService*

View File

@@ -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 (<<annotations>>) 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 <<message-header-accessor>>), used to build messages via `MessageBuilder` (see <<message-builder>>).
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 <<control-bus>>), by their role using the `SmartLifecycleRoleController` (see <<endpoint-roles>>) 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.