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
new file mode 100644
index 0000000000..2f0db8a10d
--- /dev/null
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/EnablePublisher.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.integration.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.context.annotation.Import;
+
+/**
+ * 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 has to be configured as the {@code value} of this annotation.
+ *
+ * Note: the {@link org.springframework.integration.annotation.Publisher} annotation is enabled by default via
+ * {@link EnableIntegration} processing, but there is no hook to configure the {@code default-publisher-channel}.
+ *
+ * @author Artem Bilan
+ * @since 4.0
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Import(PublisherRegistrar.class)
+public @interface EnablePublisher {
+
+ /**
+ * @return the {@code default-publisher-channel} name.
+ */
+ String value();
+}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java
index 3266247181..511f1f25c6 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java
@@ -21,7 +21,6 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
@@ -51,7 +50,6 @@ import org.springframework.integration.expression.IntegrationEvaluationContextAw
import org.springframework.integration.support.DefaultMessageBuilderFactory;
import org.springframework.integration.support.converter.DefaultDatatypeChannelMessageConverter;
import org.springframework.util.ClassUtils;
-import org.springframework.util.StringUtils;
/**
* {@link ImportBeanDefinitionRegistrar} implementation that configures integration infrastructure.
@@ -302,20 +300,7 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
registry.registerBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME, builder.getBeanDefinition());
}
- if (!registry.containsBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME)) {
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PublisherAnnotationBeanPostProcessor.class)
- .setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
-
- Map attrs = meta.getAnnotationAttributes(EnableIntegration.class.getName());
-
- String defaultPublisherChannel = (String) attrs.get("defaultPublisherChannel");
- if (StringUtils.hasText(defaultPublisherChannel)) {
- builder.addPropertyReference("defaultChannel", defaultPublisherChannel);
- }
-
- registry.registerBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME, builder.getBeanDefinition());
- }
-
+ new PublisherRegistrar().registerBeanDefinitions(meta, registry);
}
/**
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
new file mode 100644
index 0000000000..49fa77a297
--- /dev/null
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/PublisherRegistrar.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2014 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.integration.config;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.integration.aop.PublisherAnnotationBeanPostProcessor;
+import org.springframework.integration.context.IntegrationContextUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * @author Artem Bilan
+ * @since 4.0
+ */
+public class PublisherRegistrar implements ImportBeanDefinitionRegistrar {
+
+ private static final Log logger = LogFactory.getLog(PublisherRegistrar.class);
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
+ Map annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnablePublisher.class.getName());
+ if (annotationAttributes == null) {
+ return;
+ }
+ String value = (String) annotationAttributes.get("value");
+ if (!registry.containsBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME)) {
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PublisherAnnotationBeanPostProcessor.class)
+ .setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+
+ if (StringUtils.hasText(value)) {
+ builder.addPropertyReference("defaultChannel", value);
+ if (logger.isInfoEnabled()) {
+ logger.info("Setting '@Publisher' default-output-channel to '" + value + "'.");
+ }
+ }
+
+ registry.registerBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME, builder.getBeanDefinition());
+ }
+ else {
+ BeanDefinition beanDefinition = registry.getBeanDefinition(IntegrationContextUtils.PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME);
+ MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
+ RuntimeBeanReference defaultChannel = (RuntimeBeanReference) propertyValues.getPropertyValue("defaultChannel").getValue();
+ if (StringUtils.hasText(value)) {
+ if (defaultChannel == null) {
+ propertyValues.addPropertyValue("defaultChannel", new RuntimeBeanReference(value));
+ if (logger.isInfoEnabled()) {
+ logger.info("Setting '@Publisher' default-output-channel to '" + value + "'.");
+ }
+ }
+ else if (!value.equals(defaultChannel.getBeanName())) {
+ 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.");
+ }
+ }
+ }
+ }
+
+}
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 4dd70cf4c2..3147f73f7e 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
@@ -41,7 +41,7 @@ public class AnnotationConfigParser implements BeanDefinitionParser {
@Override
public Map getAnnotationAttributes(String annotationType) {
- return Collections. singletonMap("defaultPublisherChannel", element.getAttribute("default-publisher-channel"));
+ return Collections. singletonMap("value", element.getAttribute("default-publisher-channel"));
}
}, parserContext.getRegistry());
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 38ca103759..9bcd29be09 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
@@ -8,4 +8,6 @@
+
+
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 4c758df43f..ee9c637150 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
@@ -47,6 +47,7 @@ import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.config.EnableMessageHistory;
+import org.springframework.integration.config.EnablePublisher;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.history.MessageHistoryConfigurer;
import org.springframework.integration.support.MessageBuilder;
@@ -152,6 +153,7 @@ public class EnableIntegrationTests {
@EnableIntegration
@ImportResource("classpath:org/springframework/integration/configuration/EnableIntegrationTests-context.xml")
@EnableMessageHistory("${message.history.tracked.components}")
+ @EnablePublisher("publishedChannel")
public static class ContextConfiguration2 {
@Bean
@@ -175,7 +177,7 @@ public class EnableIntegrationTests {
public static class AnnotationTestService {
@ServiceActivator(inputChannel = "input", outputChannel = "output")
- @Publisher(channel = "publishedChannel")
+ @Publisher
@Payload("#args[0].toLowerCase()")
public String handle(String payload) {
return payload.toUpperCase();
diff --git a/src/reference/docbook/overview.xml b/src/reference/docbook/overview.xml
index 0b9b7775c6..c5ffbbd2d7 100644
--- a/src/reference/docbook/overview.xml
+++ b/src/reference/docbook/overview.xml
@@ -345,12 +345,20 @@
components to be declared once only, in the parent context.
- The @IntegrationComponentScan annotation has also been introduced to permit classpath
+ The @IntegrationComponentScan annotation has also been introduced to permit classpath
scanning. This annotation plays a similar role as the standard Spring Framework @ComponentScan annotation,
but it is restricted just to Spring Integration specific components and annotations,
which aren't reachable by the standard Spring Framework component scan mechanism.
For example .
-
+
+
+ The @EnablePublisher annotation has been introduced to register a
+ PublisherAnnotationBeanPostProcessor bean and configure the default-publisher-channel
+ for those @Publisher annotations which are provided without a channel attribute.
+ If more than one @EnablePublisher annotation is found, they must all have the same value
+ for the default channel.
+ See for more information.
+
diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml
index 41bc362a7d..b0acab053f 100644
--- a/src/reference/docbook/whats-new.xml
+++ b/src/reference/docbook/whats-new.xml
@@ -65,6 +65,14 @@
>Spring Boot - AutoConfigure.
+
+ @EnablePublisher
+
+ The @EnablePublisher annotation has been added, to allow the specification of a
+ default-publisher-channel for @Publisher annotations.
+ See for more information.
+
+
Redis Channel Message Stores