Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

INT-3829: Care about @Profile on the @Bean #1571

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -67,7 +67,7 @@ public boolean beforeReceive(MessageSource<?> source) {
}

@Override
public Message<?> afterReceive(Message<?> result, MessageSource<?> aource) {
public Message<?> afterReceive(Message<?> result, MessageSource<?> source) {
if (result == null) {
this.trigger.setPeriod(this.idlePollPeriod);
}
Expand Down
Expand Up @@ -31,6 +31,7 @@
import org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionValidationException;
import org.springframework.context.annotation.Bean;
Expand Down Expand Up @@ -122,6 +123,16 @@ public AbstractMethodAnnotationPostProcessor(ListableBeanFactory beanFactory, En

@Override
public Object postProcess(Object bean, String beanName, Method method, List<Annotation> annotations) {
if (this.beanAnnotationAware() && AnnotatedElementUtils.isAnnotated(method, Bean.class.getName())) {
try {
resolveTargetBeanFromMethodWithBeanAnnotation(method);
}
catch (NoSuchBeanDefinitionException e) {
// Skip the @Bean for farther endpoint processing.
// Mainly by the @Conditional reason.
return null;
}
}
MessageHandler handler = createHandler(bean, method, annotations);
setAdviceChainIfPresent(beanName, annotations, handler);
if (handler instanceof Orderable) {
Expand Down
Expand Up @@ -21,6 +21,7 @@
import java.util.List;

import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
Expand Down Expand Up @@ -59,7 +60,15 @@ public Object postProcess(Object bean, String beanName, Method method, List<Anno
String channelName = MessagingAnnotationUtils.resolveAttribute(annotations, AnnotationUtils.VALUE, String.class);
Assert.hasText(channelName, "The channel ('value' attribute of @InboundChannelAdapter) can't be empty.");

MessageSource<?> messageSource = this.createMessageSource(bean, beanName, method);
MessageSource<?> messageSource = null;
try {
messageSource = createMessageSource(bean, beanName, method);
}
catch (NoSuchBeanDefinitionException e) {
// Skip the @Bean for farther endpoint processing.
// Mainly by the @Conditional reason.
return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add a DEBUG log here - just in case, in future, it's some other bean that's missing (not the @Bean).

It's ok in the abstract class because we're only looking for the @Bean there (instead of the more general create... method). However, it won't hurt to add a DEBUG (or TRACE) log there too.

}

MessageChannel channel = this.channelResolver.resolveDestination(channelName);

Expand Down
Expand Up @@ -20,6 +20,7 @@
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
Expand All @@ -36,16 +37,20 @@

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.support.BeanDefinitionValidationException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.integration.aggregator.AggregatingMessageHandler;
import org.springframework.integration.aggregator.ExpressionEvaluatingCorrelationStrategy;
import org.springframework.integration.aggregator.ExpressionEvaluatingReleaseStrategy;
import org.springframework.integration.aggregator.SimpleMessageGroupProcessor;
import org.springframework.integration.annotation.BridgeFrom;
import org.springframework.integration.annotation.BridgeTo;
import org.springframework.integration.annotation.Filter;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.integration.annotation.Poller;
Expand Down Expand Up @@ -93,6 +98,22 @@ public class MessagingAnnotationsWithBeanAnnotationTests {
@Resource(name="collector")
private List<Message<?>> collector;

@Autowired(required = false)
@Qualifier("skippedMessageHandler")
private MessageHandler skippedMessageHandler;

@Autowired(required = false)
@Qualifier("skippedChannel")
private MessageChannel skippedChannel;

@Autowired(required = false)
@Qualifier("skippedChannel2")
private MessageChannel skippedChannel2;

@Autowired(required = false)
@Qualifier("skippedMessageSource")
private MessageSource<?> skippedMessageSource;

@Test
public void testMessagingAnnotationsFlow() {
this.sourcePollingChannelAdapter.start();
Expand All @@ -113,6 +134,11 @@ public void testMessagingAnnotationsFlow() {
assertThat(messageHistoryString, Matchers.containsString("serviceChannel"));
assertThat(messageHistoryString, Matchers.not(Matchers.containsString("discardChannel")));
}

assertNull(this.skippedMessageHandler);
assertNull(this.skippedChannel);
assertNull(this.skippedChannel2);
assertNull(this.skippedMessageSource);
}

@Test
Expand Down Expand Up @@ -237,6 +263,38 @@ public void handleMessage(Message<?> message) throws MessagingException {
};
}

@Bean
@ServiceActivator(inputChannel = "skippedChannel")
@Splitter(inputChannel = "skippedChannel2")
@Router(inputChannel = "skippedChannel3")
@Transformer(inputChannel = "skippedChannel4")
@Filter(inputChannel = "skippedChannel5")
@Profile("foo")
public MessageHandler skippedMessageHandler() {
return System.out::println;
}

@Bean
@BridgeFrom("skippedChannel6")
@Profile("foo")
public MessageChannel skippedChannel1() {
return new DirectChannel();
}

@Bean
@BridgeTo
@Profile("foo")
public MessageChannel skippedChannel2() {
return new DirectChannel();
}

@Bean
@InboundChannelAdapter("serviceChannel")
@Profile("foo")
public MessageSource<?> skippedMessageSource() {
return () -> new GenericMessage<>("foo");
}

}

@Configuration
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
Expand Down Expand Up @@ -206,7 +206,7 @@ public void run() {
}
});
}
latch.await(10, TimeUnit.SECONDS);
latch.await(30, TimeUnit.SECONDS);
for (int i = 0; i < numRequests; i++) {
assertEquals("test-" + i + "!!!", results[i]);
}
Expand Down
Expand Up @@ -22,8 +22,8 @@
<beans:property name="serviceInterface" value="org.springframework.integration.gateway.TestService"/>
<beans:property name="defaultRequestChannel" ref="requestChannel"/>
<beans:property name="defaultReplyChannel" ref="replyChannel"/>
<beans:property name="defaultRequestTimeout" value="5000"/>
<beans:property name="defaultReplyTimeout" value="5000"/>
<beans:property name="defaultRequestTimeout" value="10000"/>
<beans:property name="defaultReplyTimeout" value="10000"/>
</beans:bean>

<beans:bean id="handler" class="org.springframework.integration.gateway.TestHandler"/>
Expand Down
16 changes: 15 additions & 1 deletion src/reference/asciidoc/configuration.adoc
Expand Up @@ -16,7 +16,7 @@ Direct usage of the API is of course always an option, but we expect that most u
=== Namespace Support

Spring Integration components can be configured with XML elements that map directly to the terminology and concepts of enterprise integration.
In many cases, the element names match those of thehttp://www.eaipatterns.com[Enterprise Integration Patterns].
In many cases, the element names match those of the http://www.eaipatterns.com[Enterprise Integration Patterns].

To enable Spring Integration's core namespace support within your Spring configuration files, add the following namespace reference and schema mapping in your top-level 'beans' element:

Expand Down Expand Up @@ -532,6 +532,20 @@ For example the endpoint (`SourcePollingChannelAdapter`) for the `consoleSource(

IMPORTANT: When using these annotations on `@Bean` definitions, the `inputChannel` must reference a declared bean; channels are not automatically declared in this case.

NOTE: With Java & Annotation configuration we can use any `@Conditional` (e.g. `@Profile`) definition on the `@Bean`
method level, meaning to skip the bean registration by some condition reason:
[source,java]
----
@Bean
@ServiceActivator(inputChannel = "skippedChannel")
@Profile("foo")
public MessageHandler skipped() {
return System.out::println;
}
----
Together with the existing Spring Container logic, the Messaging Endpoint bean, based on the `@ServiceActivator`
annotation, won't be registered as well.

==== Creating a Bridge with Annotations

Starting with _version 4.0_, the Messaging Annotation and Java configuration provides `@BridgeFrom` and `@BridgeTo` `@Bean` method annotations to mark `MessageChannel` beans in `@Configuration` classes.
Expand Down