INT-4565: Fix IntComponentScan for profiles (#2652)

* INT-4565: Fix IntComponentScan for profiles

JIRA: https://jira.spring.io/browse/INT-4565

* Propagate an `Environment` to the internal `ClassPathScanningCandidateComponentProvider`
in the `IntegrationComponentScanRegistrar` for proper profiles activation
* Ensure the logic works in the `GatewayInterfaceTests`
* Some polishing and performance improvement for the `GatewayInterfaceTests`
* Add a note about `@Profile` in the `gateway.adoc`
* Polishing for the `gateway.adoc`

**Cherry-pick to 5.0.x & 4.3.x**

* * Add not activated by profile gateway interface into the `GatewayInterfaceTests`
* More `GatewayInterfaceTests` polishing
* Fix typo in the `gateway.adoc`

* Fix Checkstyle violation
This commit is contained in:
Artem Bilan
2018-12-06 15:41:40 -05:00
committed by Gary Russell
parent 2cde493fbf
commit 536b6b1786
3 changed files with 97 additions and 71 deletions

View File

@@ -61,12 +61,14 @@ import org.springframework.util.StringUtils;
*
* @author Artem Bilan
* @author Gary Russell
*
* @since 4.0
*/
public class IntegrationComponentScanRegistrar implements ImportBeanDefinitionRegistrar,
ResourceLoaderAware, EnvironmentAware {
private final Map<TypeFilter, ImportBeanDefinitionRegistrar> componentRegistrars = new HashMap<TypeFilter, ImportBeanDefinitionRegistrar>();
private final Map<TypeFilter, ImportBeanDefinitionRegistrar> componentRegistrars =
new HashMap<TypeFilter, ImportBeanDefinitionRegistrar>();
private ResourceLoader resourceLoader;
@@ -98,14 +100,16 @@ public class IntegrationComponentScanRegistrar implements ImportBeanDefinitionRe
basePackages = Collections.singleton(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
}
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(false, this.environment) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isIndependent()
&& !beanDefinition.getMetadata().isAnnotation();
}
};
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isIndependent()
&& !beanDefinition.getMetadata().isAnnotation();
}
};
if ((boolean) componentScan.get("useDefaultFilters")) { // NOSONAR - never null
for (TypeFilter typeFilter : this.componentRegistrars.keySet()) {

View File

@@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
@@ -59,6 +60,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Profile;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
@@ -77,6 +79,7 @@ import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.context.IntegrationProperties;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.handler.BridgeHandler;
import org.springframework.integration.handler.DelayHandler;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.lang.Nullable;
@@ -93,6 +96,7 @@ import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.concurrent.ListenableFuture;
@@ -107,6 +111,7 @@ import org.springframework.util.concurrent.ListenableFutureCallback;
@ContextConfiguration(classes = GatewayInterfaceTests.TestConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
@ActiveProfiles("gatewayTest")
public class GatewayInterfaceTests {
private static final String IGNORE_HEADER = "ignoreHeader";
@@ -153,20 +158,23 @@ public class GatewayInterfaceTests {
@Autowired
private IgnoredHeaderGateway ignoredHeaderGateway;
@Autowired(required = false)
private NotActivatedByProfileGateway notActivatedByProfileGateway;
@Test
public void testWithServiceSuperclassAnnotatedMethod() throws Exception {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelFoo", DirectChannel.class);
final Method fooMethod = Foo.class.getMethod("foo", String.class);
final AtomicBoolean called = new AtomicBoolean();
MessageHandler handler = message -> {
assertThat((String) message.getHeaders().get("name"), equalTo("foo"));
assertThat(
(String) message.getHeaders().get("string"),
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Foo.foo(java.lang.String)"));
assertThat((Method) message.getHeaders().get("object"), equalTo(fooMethod));
assertThat((String) message.getPayload(), equalTo("hello"));
assertThat(message.getHeaders().get("name"), equalTo("foo"));
assertThat(message.getHeaders().get("string"),
equalTo("public abstract void org.springframework.integration.gateway." +
"GatewayInterfaceTests$Foo.foo(java.lang.String)"));
assertThat(message.getHeaders().get("object"), equalTo(fooMethod));
assertThat(message.getPayload(), equalTo("hello"));
assertThat(new MessageHeaderAccessor(message).getErrorChannel(), equalTo("errorChannel"));
called.set(true);
};
@@ -181,18 +189,18 @@ public class GatewayInterfaceTests {
@Test
public void testWithServiceSuperclassAnnotatedMethodOverridePE() throws Exception {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests2-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests2-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelFoo", DirectChannel.class);
final Method fooMethod = Foo.class.getMethod("foo", String.class);
final AtomicBoolean called = new AtomicBoolean();
MessageHandler handler = message -> {
assertThat((String) message.getHeaders().get("name"), equalTo("foo"));
assertThat(
(String) message.getHeaders().get("string"),
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Foo.foo(java.lang.String)"));
assertThat((Method) message.getHeaders().get("object"), equalTo(fooMethod));
assertThat((String) message.getPayload(), equalTo("foo"));
assertThat(message.getHeaders().get("name"), equalTo("foo"));
assertThat(message.getHeaders().get("string"),
equalTo("public abstract void org.springframework.integration.gateway." +
"GatewayInterfaceTests$Foo.foo(java.lang.String)"));
assertThat(message.getHeaders().get("object"), equalTo(fooMethod));
assertThat(message.getPayload(), equalTo("foo"));
called.set(true);
};
channel.subscribe(handler);
@@ -204,8 +212,8 @@ public class GatewayInterfaceTests {
@Test
public void testWithServiceAnnotatedMethod() {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelBar", DirectChannel.class);
MessageHandler handler = mock(MessageHandler.class);
channel.subscribe(handler);
@@ -217,15 +225,16 @@ public class GatewayInterfaceTests {
@Test
public void testWithServiceSuperclassUnAnnotatedMethod() throws Exception {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
final Method bazMethod = Foo.class.getMethod("baz", String.class);
final AtomicBoolean called = new AtomicBoolean();
MessageHandler handler = message -> {
assertThat(message.getHeaders().get("name"), equalTo("overrideGlobal"));
assertThat(message.getHeaders().get("string"),
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Foo.baz(java.lang.String)"));
equalTo("public abstract void org.springframework.integration.gateway." +
"GatewayInterfaceTests$Foo.baz(java.lang.String)"));
assertThat(message.getHeaders().get("object"), equalTo(bazMethod));
assertThat(message.getPayload(), equalTo("hello"));
called.set(true);
@@ -239,15 +248,16 @@ public class GatewayInterfaceTests {
@Test
public void testWithServiceUnAnnotatedMethodGlobalHeaderDoesntOverride() throws Exception {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
final Method quxMethod = Bar.class.getMethod("qux", String.class, String.class);
final AtomicBoolean called = new AtomicBoolean();
MessageHandler handler = message -> {
assertThat(message.getHeaders().get("name"), equalTo("arg1"));
assertThat(message.getHeaders().get("string"),
equalTo("public abstract void org.springframework.integration.gateway.GatewayInterfaceTests$Bar.qux(java.lang.String,java.lang.String)"));
equalTo("public abstract void org.springframework.integration.gateway." +
"GatewayInterfaceTests$Bar.qux(java.lang.String,java.lang.String)"));
assertThat(message.getHeaders().get("object"), equalTo(quxMethod));
assertThat(message.getPayload(), equalTo("hello"));
called.set(true);
@@ -261,8 +271,8 @@ public class GatewayInterfaceTests {
@Test
public void testWithServiceCastAsSuperclassAnnotatedMethod() {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelFoo", DirectChannel.class);
MessageHandler handler = mock(MessageHandler.class);
channel.subscribe(handler);
@@ -274,8 +284,8 @@ public class GatewayInterfaceTests {
@Test
public void testWithServiceCastAsSuperclassUnAnnotatedMethod() {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
MessageHandler handler = mock(MessageHandler.class);
channel.subscribe(handler);
@@ -287,8 +297,8 @@ public class GatewayInterfaceTests {
@Test
public void testWithServiceHashcode() {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
MessageHandler handler = mock(MessageHandler.class);
channel.subscribe(handler);
@@ -300,8 +310,8 @@ public class GatewayInterfaceTests {
@Test
public void testWithServiceToString() {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
MessageHandler handler = mock(MessageHandler.class);
channel.subscribe(handler);
@@ -313,13 +323,13 @@ public class GatewayInterfaceTests {
@Test
public void testWithServiceEquals() throws Exception {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
MessageHandler handler = mock(MessageHandler.class);
channel.subscribe(handler);
Bar bar = ac.getBean(Bar.class);
assertTrue(bar.equals(ac.getBean(Bar.class)));
assertSame(bar, ac.getBean(Bar.class));
GatewayProxyFactoryBean fb = new GatewayProxyFactoryBean(Bar.class);
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerSingleton("requestChannelBar", channel);
@@ -327,15 +337,15 @@ public class GatewayInterfaceTests {
bf.registerSingleton("requestChannelFoo", channel);
fb.setBeanFactory(bf);
fb.afterPropertiesSet();
assertFalse(bar.equals(fb.getObject()));
assertNotSame(bar, fb.getObject());
verify(handler, times(0)).handleMessage(Mockito.any(Message.class));
ac.close();
}
@Test
public void testWithServiceGetClass() {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
MessageHandler handler = mock(MessageHandler.class);
channel.subscribe(handler);
@@ -352,12 +362,12 @@ public class GatewayInterfaceTests {
@Test
public void testWithCustomMapper() {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", this
.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DirectChannel channel = ac.getBean("requestChannelBaz", DirectChannel.class);
final AtomicBoolean called = new AtomicBoolean();
MessageHandler handler = message -> {
assertThat((String) message.getPayload(), equalTo("fizbuz"));
assertThat(message.getPayload(), equalTo("fizbuz"));
called.set(true);
};
channel.subscribe(handler);
@@ -369,8 +379,13 @@ public class GatewayInterfaceTests {
@Test
public void testLateReply() {
ConfigurableApplicationContext ac = new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml",
this.getClass());
ConfigurableApplicationContext ac =
new ClassPathXmlApplicationContext("GatewayInterfaceTests-context.xml", getClass());
DelayHandler delayHandler = ac.getBean(DelayHandler.class);
delayHandler.setMaxAttempts(2);
delayHandler.setRetryDelay(10);
Bar baz = ac.getBean(Bar.class);
String reply = baz.lateReply("hello", 1000, 0);
assertNull(reply);
@@ -448,14 +463,15 @@ public class GatewayInterfaceTests {
@SuppressWarnings("rawtypes")
public void testAnnotationGatewayProxyFactoryBean() {
assertNotNull(this.gatewayByAnnotationGPFB);
assertNull(this.notActivatedByProfileGateway);
assertSame(this.exec, this.annotationGatewayProxyFactoryBean.getAsyncExecutor());
assertEquals(1111L, TestUtils
.getPropertyValue(this.annotationGatewayProxyFactoryBean, "defaultRequestTimeout", Expression.class)
.getValue());
assertEquals(222L, TestUtils
.getPropertyValue(this.annotationGatewayProxyFactoryBean, "defaultReplyTimeout", Expression.class)
.getValue());
assertEquals(1111L,
TestUtils.getPropertyValue(this.annotationGatewayProxyFactoryBean,
"defaultRequestTimeout", Expression.class).getValue());
assertEquals(222L,
TestUtils.getPropertyValue(this.annotationGatewayProxyFactoryBean,
"defaultReplyTimeout", Expression.class).getValue());
Collection<MessagingGatewaySupport> messagingGateways =
this.annotationGatewayProxyFactoryBean.getGateways().values();
@@ -563,7 +579,7 @@ public class GatewayInterfaceTests {
public static class BazMapper implements MethodArgsMessageMapper {
@Override
public Message<?> toMessage(MethodArgsHolder object, @Nullable Map<String, Object> headers) throws Exception {
public Message<?> toMessage(MethodArgsHolder object, @Nullable Map<String, Object> headers) {
return MessageBuilder.withPayload("fizbuz")
.copyHeadersIfAbsent(headers)
.build();
@@ -652,6 +668,7 @@ public class GatewayInterfaceTests {
@MessagingGateway
@TestMessagingGateway
@Profile("gatewayTest")
public interface Int2634Gateway {
@Gateway(requestChannel = "gatewayChannel", payloadExpression = "#args[0]")
@@ -665,6 +682,15 @@ public class GatewayInterfaceTests {
}
@MessagingGateway(defaultRequestChannel = "errorChannel")
@TestMessagingGateway
@Profile("notActiveProfile")
public interface NotActivatedByProfileGateway {
void send(String payload);
}
@MessagingGateway(asyncExecutor = "exec")
@TestMessagingGateway
public interface ExecGateway {