diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java index acc6cf3287..f7df98d90c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aop/PublisherAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -16,26 +16,19 @@ package org.springframework.integration.aop; -import java.util.Collections; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.springframework.aop.framework.Advised; -import org.springframework.aop.framework.ProxyConfig; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.aop.framework.autoproxy.AbstractBeanFactoryAwareAdvisingPostProcessor; +import org.springframework.beans.factory.BeanCreationNotAllowedException; import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.core.Ordered; -import org.springframework.util.ClassUtils; +import org.springframework.beans.factory.NoUniqueBeanDefinitionException; /** * Post-processes beans that contain the * method-level @{@link org.springframework.integration.annotation.Publisher} annotation. + *

+ * Only one bean instance of this processor can be declared in the application context, manual + * or automatic by thr framework via annotation or XML processing. * * @author Oleg Zhurakousky * @author Mark Fisher @@ -46,21 +39,14 @@ import org.springframework.util.ClassUtils; * @since 2.0 */ @SuppressWarnings("serial") -public class PublisherAnnotationBeanPostProcessor extends ProxyConfig - implements BeanPostProcessor, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, Ordered { +public class PublisherAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor + implements BeanNameAware, InitializingBean { - private volatile String defaultChannelName; + private String defaultChannelName; - private volatile PublisherAnnotationAdvisor advisor; + private String name; - private volatile int order = Ordered.LOWEST_PRECEDENCE; - - private volatile BeanFactory beanFactory; - - private volatile ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); - - private final Set> nonApplicableCache = - Collections.newSetFromMap(new ConcurrentHashMap, Boolean>(256)); + private BeanFactory beanFactory; /** * Set the default channel where Messages should be sent if the annotation @@ -72,64 +58,32 @@ public class PublisherAnnotationBeanPostProcessor extends ProxyConfig this.defaultChannelName = defaultChannelName; } + @Override + public void setBeanName(String name) { + this.name = name; + } + @Override public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; + super.setBeanFactory(beanFactory); + PublisherAnnotationAdvisor publisherAnnotationAdvisor = new PublisherAnnotationAdvisor(); + publisherAnnotationAdvisor.setBeanFactory(beanFactory); + publisherAnnotationAdvisor.setDefaultChannelName(this.defaultChannelName); + this.advisor = publisherAnnotationAdvisor; } @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - - public void setOrder(int order) { - this.order = order; - } - - @Override - public int getOrder() { - return this.order; - } - - @Override - public void afterPropertiesSet() { - this.advisor = new PublisherAnnotationAdvisor(); - this.advisor.setBeanFactory(this.beanFactory); - this.advisor.setDefaultChannelName(this.defaultChannelName); - } - - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - return bean; - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - Class targetClass = AopUtils.getTargetClass(bean); - - // the set will hold records of prior class scans and will contain the bean classes that can not - // be assigned to the Advisor interface and therefore can be short circuited - if (this.nonApplicableCache.contains(targetClass)) { - return bean; + public void afterPropertiesSet() throws Exception { + try { + this.beanFactory.getBean(PublisherAnnotationBeanPostProcessor.class); } - - if (AopUtils.canApply(this.advisor, targetClass)) { - if (bean instanceof Advised) { - ((Advised) bean).addAdvisor(this.advisor); - return bean; - } - else { - ProxyFactory proxyFactory = new ProxyFactory(bean); - // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig. - proxyFactory.copyFrom(this); - proxyFactory.addAdvisor(this.advisor); - return proxyFactory.getProxy(this.beanClassLoader); - } - } - else { - // cannot apply advisor - this.nonApplicableCache.add(targetClass); - return bean; + catch (NoUniqueBeanDefinitionException ex) { + throw new BeanCreationNotAllowedException(this.name, + "Only one 'PublisherAnnotationBeanPostProcessor' bean can be defined in the application context." + + " Do not use '@EnablePublisher' (or '') if you declare a" + + " 'PublisherAnnotationBeanPostProcessor' bean definition manually. " + + "Bean names found: " + ex.getBeanNamesFound()); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/EnablePublisher.java b/spring-integration-core/src/main/java/org/springframework/integration/config/EnablePublisher.java index f949d0fc70..2ab7f6b398 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/EnablePublisher.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/EnablePublisher.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2018 the original author or authors. + * Copyright 2014-2019 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. @@ -23,11 +23,15 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Import; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.AliasFor; /** - * Provides the registration for the {@link org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor} + * Provides the registration for the + * {@link org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor} * to allow the use of the {@link org.springframework.integration.annotation.Publisher} annotation. - * In addition the {@code default-publisher-channel} name can be configured as the {@code value} of this annotation. + * In addition the {@code default-publisher-channel} name can be configured as + * the {@link #defaultChannel()} of this annotation. * * @author Artem Bilan * @@ -40,7 +44,39 @@ import org.springframework.context.annotation.Import; public @interface EnablePublisher { /** - * @return the {@code default-publisher-channel} name. + * Alias for the {@link #defaultChannel()} attribute. + * The {@code default-publisher-channel} name. + * @return the channel bean name. */ + @AliasFor("defaultChannel") String value() default ""; + + /** + * The {@code default-publisher-channel} name. + * @return the channel bean name. + * @since 5.1.3 + */ + @AliasFor("value") + String defaultChannel() default ""; + + /** + * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed + * to standard Java interface-based proxies. + * @return whether proxy target class or not. + * @since 5.1.3 + */ + boolean proxyTargetClass() default false; + + /** + * Indicate the order in which the + * {@link org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor} + * should be applied. + *

The default is {@link Ordered#LOWEST_PRECEDENCE} in order to run + * after all other post-processors, so that it can add an advisor to + * existing proxies rather than double-proxy. + * @return the order for the bean post-processor. + * @since 5.1.3 + */ + int order() default Ordered.LOWEST_PRECEDENCE; + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/PublisherRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/config/PublisherRegistrar.java index eef7885560..1c53abcced 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/PublisherRegistrar.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/PublisherRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2019 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. @@ -37,6 +37,7 @@ import org.springframework.util.StringUtils; /** * @author Artem Bilan * @author Gary Russell + * * @since 4.0 */ public class PublisherRegistrar implements ImportBeanDefinitionRegistrar { @@ -48,21 +49,28 @@ public class PublisherRegistrar implements ImportBeanDefinitionRegistrar { Map annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnablePublisher.class.getName()); - String value = (annotationAttributes == null - ? (String) AnnotationUtils.getDefaultValue(EnablePublisher.class) - : (String) annotationAttributes.get("value")); + String defaultChannel = + annotationAttributes == null + ? (String) AnnotationUtils.getDefaultValue(EnablePublisher.class) + : (String) annotationAttributes.get("defaultChannel"); if (!registry.containsBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME)) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PublisherAnnotationBeanPostProcessor.class) .setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - if (StringUtils.hasText(value)) { - builder.addPropertyValue("defaultChannelName", value); + if (StringUtils.hasText(defaultChannel)) { + builder.addPropertyValue("defaultChannelName", defaultChannel); if (logger.isInfoEnabled()) { - logger.info("Setting '@Publisher' default-output-channel to '" + value + "'."); + logger.info("Setting '@Publisher' default-output-channel to '" + defaultChannel + "'."); } } + if (annotationAttributes != null) { + Object proxyTargetClass = annotationAttributes.get("proxyTargetClass"); + builder.addPropertyValue("proxyTargetClass", proxyTargetClass); + Object order = annotationAttributes.get("order"); + builder.addPropertyValue("order", order); + } registry.registerBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME, builder.getBeanDefinition()); } @@ -71,17 +79,17 @@ public class PublisherRegistrar implements ImportBeanDefinitionRegistrar { registry.getBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME); MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); PropertyValue defaultChannelPropertyValue = propertyValues.getPropertyValue("defaultChannelName"); - if (StringUtils.hasText(value)) { + if (StringUtils.hasText(defaultChannel)) { if (defaultChannelPropertyValue == null) { - propertyValues.addPropertyValue("defaultChannelName", value); + propertyValues.addPropertyValue("defaultChannelName", defaultChannel); if (logger.isInfoEnabled()) { - logger.info("Setting '@Publisher' default-output-channel to '" + value + "'."); + logger.info("Setting '@Publisher' default-output-channel to '" + defaultChannel + "'."); } } - else if (!value.equals(defaultChannelPropertyValue.getValue())) { + else if (!defaultChannel.equals(defaultChannelPropertyValue.getValue())) { throw new BeanDefinitionStoreException("When more than one enable publisher definition " + - "(@EnablePublisher or )" + - " is found in the context, they all must have the same 'default-publisher-channel' value."); + "(@EnablePublisher or ) is found in the context, " + + "they all must have the same 'default-publisher-channel' attribute value."); } } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AnnotationConfigParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AnnotationConfigParser.java index 2887a2b989..7d0c0aa7de 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AnnotationConfigParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AnnotationConfigParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -16,7 +16,7 @@ package org.springframework.integration.config.xml; -import java.util.Collections; +import java.util.HashMap; import java.util.Map; import org.w3c.dom.Element; @@ -40,8 +40,6 @@ public class AnnotationConfigParser implements BeanDefinitionParser { @Override public BeanDefinition parse(final Element element, ParserContext parserContext) { - IntegrationRegistrar integrationRegistrar = new IntegrationRegistrar(); - StandardAnnotationMetadata importingClassMetadata = new StandardAnnotationMetadata(Object.class) { @@ -51,8 +49,13 @@ public class AnnotationConfigParser implements BeanDefinitionParser { Element enablePublisherElement = DomUtils.getChildElementByTagName(element, "enable-publisher"); if (enablePublisherElement != null) { - return Collections.singletonMap("value", + Map attributes = new HashMap<>(); + attributes.put("defaultChannel", enablePublisherElement.getAttribute("default-publisher-channel")); + attributes.put("proxyTargetClass", + enablePublisherElement.getAttribute("proxy-target-class")); + attributes.put("order", enablePublisherElement.getAttribute("order")); + return attributes; } else { return null; @@ -65,7 +68,7 @@ public class AnnotationConfigParser implements BeanDefinitionParser { }; - integrationRegistrar.registerBeanDefinitions(importingClassMetadata, parserContext.getRegistry()); + new IntegrationRegistrar().registerBeanDefinitions(importingClassMetadata, parserContext.getRegistry()); return null; } diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/spring-integration-5.1.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/spring-integration-5.1.xsd index 076793afe4..70935e8728 100644 --- a/spring-integration-core/src/main/resources/org/springframework/integration/config/spring-integration-5.1.xsd +++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/spring-integration-5.1.xsd @@ -35,6 +35,30 @@ + + + + Indicate whether subclass-based (CGLIB) proxies are to be created as opposed + to standard Java interface-based proxies. + + + + + + + + + + Indicate the order in which the + 'org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor' + should be applied. + Defaults to 'org.springframework.core.Ordered.LOWEST_PRECEDENCE'. + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml index 00bde4e2ec..f0b90804bc 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml @@ -15,7 +15,7 @@ - + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java index efb28cf7ca..1e2df03cf0 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2018 the original author or authors. + * Copyright 2014-2019 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. @@ -19,6 +19,7 @@ package org.springframework.integration.configuration; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.sameInstance; @@ -51,8 +52,6 @@ import java.util.concurrent.atomic.AtomicReference; import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInterceptor; import org.apache.commons.logging.Log; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; import org.hamcrest.Matchers; import org.junit.Test; import org.junit.runner.RunWith; @@ -92,6 +91,7 @@ import org.springframework.integration.annotation.Role; import org.springframework.integration.annotation.ServiceActivator; import org.springframework.integration.annotation.Transformer; import org.springframework.integration.annotation.UseSpelInvoker; +import org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor; import org.springframework.integration.channel.AbstractMessageChannel; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.channel.NullChannel; @@ -127,7 +127,6 @@ import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageDeliveryException; import org.springframework.messaging.MessageHandler; -import org.springframework.messaging.MessagingException; import org.springframework.messaging.PollableChannel; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.messaging.support.ChannelInterceptor; @@ -295,6 +294,9 @@ public class EnableIntegrationTests { @Qualifier("enableIntegrationTests.ChildConfiguration.autoCreatedChannelMessageSource.inboundChannelAdapter") private Lifecycle autoCreatedChannelMessageSourceAdapter; + @Autowired + private PublisherAnnotationBeanPostProcessor publisherAnnotationBeanPostProcessor; + @Test public void testAnnotatedServiceActivator() throws Exception { this.serviceActivatorEndpoint.start(); @@ -666,7 +668,7 @@ public class EnableIntegrationTests { List integers = ref.get(); assertEquals(5, integers.size()); - assertThat(integers, Matchers.contains(2, 4, 6, 8, 10)); + assertThat(integers, contains(2, 4, 6, 8, 10)); } @Test @@ -744,13 +746,17 @@ public class EnableIntegrationTests { assertNotNull(receive); assertEquals(testDate, receive.getPayload()); + + assertTrue(this.publisherAnnotationBeanPostProcessor.isProxyTargetClass()); + assertEquals(Integer.MAX_VALUE - 1, this.publisherAnnotationBeanPostProcessor.getOrder()); } @Configuration @ComponentScan @IntegrationComponentScan @EnableIntegration -// INT-3853 @PropertySource("classpath:org/springframework/integration/configuration/EnableIntegrationTests.properties") + // INT-3853 + // @PropertySource("classpath:org/springframework/integration/configuration/EnableIntegrationTests.properties") @EnableMessageHistory({ "input", "publishedChannel", "annotationTestService*" }) public static class ContextConfiguration { @@ -996,7 +1002,7 @@ public class EnableIntegrationTests { @EnableIntegration @ImportResource("classpath:org/springframework/integration/configuration/EnableIntegrationTests-context.xml") @EnableMessageHistory("${message.history.tracked.components}") - @EnablePublisher("publishedChannel") + @EnablePublisher(defaultChannel = "publishedChannel") @EnableAsync public static class ContextConfiguration2 { @@ -1026,14 +1032,9 @@ public class EnableIntegrationTests { @ServiceActivator(inputChannel = "sendAsyncChannel") @Role("foo") public MessageHandler sendAsyncHandler() { - return new MessageHandler() { - - @Override - public void handleMessage(Message message) throws MessagingException { - asyncAnnotationProcessThread().set(Thread.currentThread()); - asyncAnnotationProcessLatch().countDown(); - } - + return message -> { + asyncAnnotationProcessThread().set(Thread.currentThread()); + asyncAnnotationProcessLatch().countDown(); }; } @@ -1139,7 +1140,7 @@ public class EnableIntegrationTests { @Bean public AnnotationTestService annotationTestService() { - return new AnnotationTestServiceImpl(); + return new AnnotationTestService(); } @Bean @@ -1155,7 +1156,8 @@ public class EnableIntegrationTests { @Bean @ServiceActivator(inputChannel = "myHandlerChannel", adviceChain = "myHandlerAdvice") public MessageHandler myHandler() { - return message -> { }; + return message -> { + }; } @Bean @@ -1198,53 +1200,12 @@ public class EnableIntegrationTests { } - public interface AnnotationTestService { - - String handle(String payload); - - String handle1(String payload); - - String handle2(String payload); - - String handle3(String payload); - - String handle4(String payload); - - String transform(Message message); - - String transform2(Message message); - - Integer count(); - - String foo(); - - Message message(); - - Integer annCount(); - - Integer annCount1(); - - Integer annCount2(); - - Integer annCount5(); - - Integer annCount8(); - - Integer annAgg1(List messages); - - Integer annAgg2(List messages); - - Integer multiply(Integer value); - - } - - public static class AnnotationTestServiceImpl implements Lifecycle, AnnotationTestService { + public static class AnnotationTestService implements Lifecycle { private final AtomicInteger counter = new AtomicInteger(); private boolean running; - @Override @ServiceActivator(inputChannel = "input", outputChannel = "output", autoStartup = "false", poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.interval}", @@ -1256,7 +1217,6 @@ public class EnableIntegrationTests { return payload.toUpperCase(); } - @Override @ServiceActivator(inputChannel = "input1", outputChannel = "output", poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedRate = "${poller.interval}")) @@ -1266,7 +1226,6 @@ public class EnableIntegrationTests { return payload.toUpperCase(); } - @Override @ServiceActivator(inputChannel = "input2", outputChannel = "output", poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", cron = "0 5 7 * * *")) @Publisher @@ -1275,7 +1234,6 @@ public class EnableIntegrationTests { return payload.toUpperCase(); } - @Override @ServiceActivator(inputChannel = "input3", outputChannel = "output", poller = @Poller("myPoller")) @Publisher @Payload("#args[0].toLowerCase()") @@ -1283,7 +1241,6 @@ public class EnableIntegrationTests { return payload.toUpperCase(); } - @Override @ServiceActivator(inputChannel = "input4", outputChannel = "output", poller = @Poller(trigger = "myTrigger")) @Publisher @@ -1303,7 +1260,6 @@ public class EnableIntegrationTests { return payload.toUpperCase(); }*/ - @Override @Transformer(inputChannel = "gatewayChannel") public String transform(Message message) { assertTrue(message.getHeaders().containsKey("foo")); @@ -1313,7 +1269,6 @@ public class EnableIntegrationTests { return this.handle(message.getPayload()) + Arrays.asList(new Throwable().getStackTrace()).toString(); } - @Override @Transformer(inputChannel = "gatewayChannel2") @UseSpelInvoker(compilerMode = "${xxxxxxxx:IMMEDIATE}") public String transform2(Message message) { @@ -1324,20 +1279,17 @@ public class EnableIntegrationTests { return this.handle(message.getPayload()) + "2" + Arrays.asList(new Throwable().getStackTrace()).toString(); } - @Override @MyInboundChannelAdapter1 public Integer count() { return this.counter.incrementAndGet(); } - @Override @InboundChannelAdapter(value = "fooChannel", poller = @Poller(trigger = "onlyOnceTrigger", maxMessagesPerPoll = "2")) public String foo() { return "foo"; } - @Override @InboundChannelAdapter(value = "messageChannel", poller = @Poller(fixedDelay = "${poller.interval}", maxMessagesPerPoll = "1")) public Message message() { @@ -1361,44 +1313,37 @@ public class EnableIntegrationTests { // metaAnnotation tests - @Override @MyServiceActivator public Integer annCount() { return 0; } - @Override @MyServiceActivator1(inputChannel = "annInput1", autoStartup = "true", adviceChain = { "annAdvice1" }, poller = @Poller(fixedRate = "2000")) public Integer annCount1() { return 0; } - @Override @MyServiceActivatorNoLocalAtts public Integer annCount2() { return 0; } - @Override @MyServiceActivator5 public Integer annCount5() { return 0; } - @Override @MyServiceActivator8 public Integer annCount8() { return 0; } - @Override @MyAggregator public Integer annAgg1(List messages) { return 42; } - @Override @MyAggregatorDefaultOverrideDefaults public Integer annAgg2(List messages) { return 42; @@ -1408,7 +1353,6 @@ public class EnableIntegrationTests { /*@BridgeFrom("") public void invalidBridgeAnnotationMethod(Object payload) {}*/ - @Override @ServiceActivator(inputChannel = "monoChannel") public Integer multiply(Integer value) { return value * 2; @@ -1693,25 +1637,4 @@ public class EnableIntegrationTests { } - public class RegexMatcher extends BaseMatcher { - - private final String regex; - - public RegexMatcher(String regex) { - this.regex = regex; - } - - @Override - public boolean matches(Object o) { - return ((String) o).matches(regex); - - } - - @Override - public void describeTo(Description description) { - description.appendText("matches regex="); - } - - } - } diff --git a/src/reference/asciidoc/message-publishing.adoc b/src/reference/asciidoc/message-publishing.adoc index d88de47846..47fab0c4cf 100644 --- a/src/reference/asciidoc/message-publishing.adoc +++ b/src/reference/asciidoc/message-publishing.adoc @@ -142,6 +142,8 @@ public class IntegrationConfiguration { ---- ==== +Starting with version 5.1.3, the `` component, as well as the `@EnablePublisher` annotation have the `proxy-target-class` and `order` attributes for tuning the `ProxyFactory` configuration. + Similar to other Spring annotations (`@Component`, `@Scheduled`, and so on), you can also use `@Publisher` as a meta-annotation. This means that you can define your own annotations that are treated in the same way as the `@Publisher` itself. The following example shows how to do so: @@ -321,7 +323,7 @@ Another way of handling this type of scenario is with a wire-tap. See <` XML element. diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index 0796e57151..3cb83cb55a 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -119,6 +119,7 @@ See <> for more information. ==== @Publisher annotation changes Starting with version 5.1, you must explicitly turn on the `@Publisher` AOP functionality by using `@EnablePublisher` or by using the `` child element on ``. +Also the `proxy-target-class` and `order` attributes have been added for tuning the `ProxyFactory` configuration. See <> for more information.