Some Fixes and Improvements
* Remove `durable-subscription-name` from the `JmsMessageDrivenEndpointParser`, since we don't have such an attribute any more * Fix `configuration.adoc` for various typos * Remove `spring.integration.messagingAnnotations.require.componentAnnotation` and `spring.integration.messagingGateway.convertReceiveMessage` properties and their usage, since they are not actual any more starting with SI-5.0 * Fix tests appropriately Address PR comments and more polishing Polishing
This commit is contained in:
committed by
Gary Russell
parent
370be4853d
commit
868004e9e4
@@ -356,11 +356,8 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
|
||||
*/
|
||||
private void registerMessagingAnnotationPostProcessors(AnnotationMetadata meta, BeanDefinitionRegistry registry) {
|
||||
if (!registry.containsBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME)) {
|
||||
String requireComponentAnnotationExpression =
|
||||
IntegrationProperties.getExpressionFor(IntegrationProperties.REQUIRE_COMPONENT_ANNOTATION);
|
||||
BeanDefinitionBuilder builder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(MessagingAnnotationPostProcessor.class)
|
||||
.addPropertyValue("requireComponentAnnotation", requireComponentAnnotationExpression)
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
registry.registerBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME,
|
||||
|
||||
@@ -55,7 +55,6 @@ import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.support.SmartLifecycleRoleController;
|
||||
import org.springframework.integration.util.MessagingAnnotationUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
@@ -84,7 +83,6 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
private boolean requireComponentAnnotation;
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
@@ -93,17 +91,6 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param requireComponentAnnotation the {@code boolean} flag to indicate requirements for the
|
||||
* {@link Component} annotation presentation for the messaging annotations.
|
||||
* @since 4.3
|
||||
* @see org.springframework.integration.context.IntegrationProperties#REQUIRE_COMPONENT_ANNOTATION
|
||||
*/
|
||||
public void setRequireComponentAnnotation(boolean requireComponentAnnotation) {
|
||||
this.requireComponentAnnotation = requireComponentAnnotation;
|
||||
}
|
||||
|
||||
protected ConfigurableListableBeanFactory getBeanFactory() {
|
||||
return this.beanFactory;
|
||||
}
|
||||
@@ -147,75 +134,65 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
|
||||
Assert.notNull(this.beanFactory, "BeanFactory must not be null");
|
||||
final Class<?> beanClass = this.getBeanClass(bean);
|
||||
if (this.requireComponentAnnotation && AnnotationUtils.findAnnotation(beanClass, Component.class) == null) {
|
||||
// we only post-process stereotype components
|
||||
return bean;
|
||||
}
|
||||
|
||||
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Map<Class<? extends Annotation>, List<Annotation>> annotationChains =
|
||||
new HashMap<Class<? extends Annotation>, List<Annotation>>();
|
||||
for (Class<? extends Annotation> annotationType :
|
||||
MessagingAnnotationPostProcessor.this.postProcessors.keySet()) {
|
||||
if (AnnotatedElementUtils.isAnnotated(method, annotationType.getName())) {
|
||||
List<Annotation> annotationChain = getAnnotationChain(method, annotationType);
|
||||
if (annotationChain.size() > 0) {
|
||||
annotationChains.put(annotationType, annotationChain);
|
||||
}
|
||||
ReflectionUtils.doWithMethods(beanClass, method -> {
|
||||
Map<Class<? extends Annotation>, List<Annotation>> annotationChains = new HashMap<>();
|
||||
for (Class<? extends Annotation> annotationType :
|
||||
MessagingAnnotationPostProcessor.this.postProcessors.keySet()) {
|
||||
if (AnnotatedElementUtils.isAnnotated(method, annotationType.getName())) {
|
||||
List<Annotation> annotationChain = getAnnotationChain(method, annotationType);
|
||||
if (annotationChain.size() > 0) {
|
||||
annotationChains.put(annotationType, annotationChain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<Class<? extends Annotation>, List<Annotation>> entry : annotationChains.entrySet()) {
|
||||
Class<? extends Annotation> annotationType = entry.getKey();
|
||||
List<Annotation> annotations = entry.getValue();
|
||||
MethodAnnotationPostProcessor postProcessor =
|
||||
MessagingAnnotationPostProcessor.this.postProcessors.get(annotationType);
|
||||
if (postProcessor != null && postProcessor.shouldCreateEndpoint(method, annotations)) {
|
||||
Method targetMethod = method;
|
||||
if (AopUtils.isJdkDynamicProxy(bean)) {
|
||||
try {
|
||||
targetMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new IllegalArgumentException("Service methods must be extracted to the service "
|
||||
+ "interface for JdkDynamicProxy. The affected bean is: '" + beanName + "' "
|
||||
+ "and its method: '" + method + "'", e);
|
||||
for (Entry<Class<? extends Annotation>, List<Annotation>> entry : annotationChains.entrySet()) {
|
||||
Class<? extends Annotation> annotationType = entry.getKey();
|
||||
List<Annotation> annotations = entry.getValue();
|
||||
MethodAnnotationPostProcessor<?> postProcessor =
|
||||
MessagingAnnotationPostProcessor.this.postProcessors.get(annotationType);
|
||||
if (postProcessor != null && postProcessor.shouldCreateEndpoint(method, annotations)) {
|
||||
Method targetMethod = method;
|
||||
if (AopUtils.isJdkDynamicProxy(bean)) {
|
||||
try {
|
||||
targetMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new IllegalArgumentException("Service methods must be extracted to the service "
|
||||
+ "interface for JdkDynamicProxy. The affected bean is: '" + beanName + "' "
|
||||
+ "and its method: '" + method + "'", e);
|
||||
}
|
||||
}
|
||||
Object result = postProcessor.postProcess(bean, beanName, targetMethod, annotations);
|
||||
if (result != null && result instanceof AbstractEndpoint) {
|
||||
AbstractEndpoint endpoint = (AbstractEndpoint) result;
|
||||
String autoStartup = MessagingAnnotationUtils.resolveAttribute(annotations, "autoStartup",
|
||||
String.class);
|
||||
if (StringUtils.hasText(autoStartup)) {
|
||||
autoStartup = getBeanFactory().resolveEmbeddedValue(autoStartup);
|
||||
if (StringUtils.hasText(autoStartup)) {
|
||||
endpoint.setAutoStartup(Boolean.parseBoolean(autoStartup));
|
||||
}
|
||||
}
|
||||
Object result = postProcessor.postProcess(bean, beanName, targetMethod, annotations);
|
||||
if (result != null && result instanceof AbstractEndpoint) {
|
||||
AbstractEndpoint endpoint = (AbstractEndpoint) result;
|
||||
String autoStartup = MessagingAnnotationUtils.resolveAttribute(annotations, "autoStartup",
|
||||
String.class);
|
||||
if (StringUtils.hasText(autoStartup)) {
|
||||
autoStartup = getBeanFactory().resolveEmbeddedValue(autoStartup);
|
||||
if (StringUtils.hasText(autoStartup)) {
|
||||
endpoint.setAutoStartup(Boolean.parseBoolean(autoStartup));
|
||||
}
|
||||
}
|
||||
|
||||
String phase = MessagingAnnotationUtils.resolveAttribute(annotations, "phase", String.class);
|
||||
String phase = MessagingAnnotationUtils.resolveAttribute(annotations, "phase", String.class);
|
||||
if (StringUtils.hasText(phase)) {
|
||||
phase = getBeanFactory().resolveEmbeddedValue(phase);
|
||||
if (StringUtils.hasText(phase)) {
|
||||
phase = getBeanFactory().resolveEmbeddedValue(phase);
|
||||
if (StringUtils.hasText(phase)) {
|
||||
endpoint.setPhase(Integer.parseInt(phase));
|
||||
}
|
||||
endpoint.setPhase(Integer.parseInt(phase));
|
||||
}
|
||||
}
|
||||
|
||||
String endpointBeanName = generateBeanName(beanName, method, annotationType);
|
||||
endpoint.setBeanName(endpointBeanName);
|
||||
getBeanFactory().registerSingleton(endpointBeanName, endpoint);
|
||||
getBeanFactory().initializeBean(endpoint, endpointBeanName);
|
||||
String endpointBeanName = generateBeanName(beanName, method, annotationType);
|
||||
endpoint.setBeanName(endpointBeanName);
|
||||
getBeanFactory().registerSingleton(endpointBeanName, endpoint);
|
||||
getBeanFactory().initializeBean(endpoint, endpointBeanName);
|
||||
|
||||
Role role = AnnotationUtils.findAnnotation(method, Role.class);
|
||||
if (role != null) {
|
||||
MessagingAnnotationPostProcessor.this.lazyLifecycleRoles.add(role.value(),
|
||||
endpointBeanName);
|
||||
}
|
||||
Role role = AnnotationUtils.findAnnotation(method, Role.class);
|
||||
if (role != null) {
|
||||
MessagingAnnotationPostProcessor.this.lazyLifecycleRoles.add(role.value(),
|
||||
endpointBeanName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,16 +66,6 @@ public final class IntegrationProperties {
|
||||
*/
|
||||
public static final String THROW_EXCEPTION_ON_LATE_REPLY = INTEGRATION_PROPERTIES_PREFIX + "messagingTemplate.throwExceptionOnLateReply";
|
||||
|
||||
/**
|
||||
* Specifies the value of {@link org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor#requireComponentAnnotation}.
|
||||
*/
|
||||
public static final String REQUIRE_COMPONENT_ANNOTATION = INTEGRATION_PROPERTIES_PREFIX + "messagingAnnotations.require.componentAnnotation";
|
||||
|
||||
/**
|
||||
* Specifies the value of {@link org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor#requireComponentAnnotation}.
|
||||
*/
|
||||
public static final String GATEWAY_CONVERT_RECEIVE_MESSAGE = INTEGRATION_PROPERTIES_PREFIX + "messagingGateway.convertReceiveMessage";
|
||||
|
||||
private static Properties defaults;
|
||||
|
||||
static {
|
||||
|
||||
@@ -47,7 +47,6 @@ import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.annotation.Gateway;
|
||||
import org.springframework.integration.annotation.GatewayHeader;
|
||||
import org.springframework.integration.context.IntegrationProperties;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.support.channel.BeanFactoryChannelResolver;
|
||||
import org.springframework.integration.support.management.TrackableComponent;
|
||||
@@ -130,8 +129,6 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
|
||||
|
||||
private volatile MethodArgsMessageMapper argsMapper;
|
||||
|
||||
private volatile boolean convertReceiveMessage;
|
||||
|
||||
/**
|
||||
* Create a Factory whose service interface type can be configured by setter injection.
|
||||
* If none is set, it will fall back to the default service interface type,
|
||||
@@ -343,8 +340,6 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
|
||||
}
|
||||
}
|
||||
|
||||
this.convertReceiveMessage =
|
||||
getIntegrationProperty(IntegrationProperties.GATEWAY_CONVERT_RECEIVE_MESSAGE, Boolean.class);
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
@@ -434,12 +429,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
|
||||
if (paramCount == 0 && !hasPayloadExpression) {
|
||||
if (shouldReply) {
|
||||
if (shouldReturnMessage) {
|
||||
if (this.convertReceiveMessage) {
|
||||
return gateway.receive();
|
||||
}
|
||||
else {
|
||||
return gateway.receiveMessage();
|
||||
}
|
||||
return gateway.receiveMessage();
|
||||
}
|
||||
response = gateway.receive();
|
||||
}
|
||||
|
||||
@@ -3,5 +3,3 @@ spring.integration.channels.maxUnicastSubscribers=0x7fffffff
|
||||
spring.integration.channels.maxBroadcastSubscribers=0x7fffffff
|
||||
spring.integration.taskScheduler.poolSize=10
|
||||
spring.integration.messagingTemplate.throwExceptionOnLateReply=false
|
||||
spring.integration.messagingAnnotations.require.componentAnnotation=false
|
||||
spring.integration.messagingGateway.convertReceiveMessage=false
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
|
||||
<annotation-config/> <!-- Second declaration should not be a problem - see INT-3445 -->
|
||||
|
||||
<util:properties id="integrationGlobalProperties">
|
||||
<beans:prop key="spring.integration.messagingAnnotations.require.componentAnnotation">true</beans:prop>
|
||||
</util:properties>
|
||||
|
||||
<beans:bean id="annotatedEndpoint"
|
||||
class="org.springframework.integration.config.annotation.AnnotatedEndpointActivationTests.AnnotatedEndpoint"/>
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.integration.config.annotation;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -80,7 +79,7 @@ public class AnnotatedEndpointActivationTests {
|
||||
assertEquals(1, count);
|
||||
|
||||
assertTrue(this.applicationContext.containsBean("annotatedEndpoint.process.serviceActivator"));
|
||||
assertFalse(this.applicationContext.containsBean("annotatedEndpoint2.process.serviceActivator"));
|
||||
assertTrue(this.applicationContext.containsBean("annotatedEndpoint2.process.serviceActivator"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,20 +16,14 @@
|
||||
|
||||
package org.springframework.integration.gateway;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.willAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -50,8 +44,6 @@ import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.context.IntegrationContextUtils;
|
||||
import org.springframework.integration.context.IntegrationProperties;
|
||||
import org.springframework.integration.endpoint.EventDrivenConsumer;
|
||||
import org.springframework.integration.support.utils.IntegrationUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -161,41 +153,6 @@ public class GatewayProxyFactoryBeanTests {
|
||||
assertEquals("foo", message.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReceiveMessageConvert() throws Exception {
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
replyChannel.send(new GenericMessage<>("foo"));
|
||||
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean();
|
||||
proxyFactory.setServiceInterface(TestService.class);
|
||||
proxyFactory.setDefaultReplyChannel(replyChannel);
|
||||
|
||||
BeanFactory beanFactory = mock(BeanFactory.class);
|
||||
|
||||
given(beanFactory.containsBean(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME))
|
||||
.willReturn(true);
|
||||
|
||||
willAnswer(invocation -> {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(IntegrationProperties.GATEWAY_CONVERT_RECEIVE_MESSAGE, "true");
|
||||
return properties;
|
||||
})
|
||||
.given(beanFactory)
|
||||
.getBean(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME, Properties.class);
|
||||
|
||||
proxyFactory.setBeanFactory(beanFactory);
|
||||
proxyFactory.afterPropertiesSet();
|
||||
TestService service = (TestService) proxyFactory.getObject();
|
||||
try {
|
||||
service.getMessage();
|
||||
fail("ClassCastException expected");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e, instanceOf(ClassCastException.class));
|
||||
assertThat(e.getMessage(),
|
||||
containsString("java.lang.String cannot be cast to org.springframework.messaging.Message"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestReplyWithTypeConversion() throws Exception {
|
||||
final QueueChannel requestChannel = new QueueChannel();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -68,7 +68,7 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
|
||||
"max-messages-per-task", "selector",
|
||||
"receive-timeout", "recovery-interval",
|
||||
"idle-consumer-limit", "idle-task-execution-limit",
|
||||
"cache-level", "subscription-durable", "durable-subscription-name",
|
||||
"cache-level", "subscription-durable",
|
||||
"subscription-shared", "subscription-name",
|
||||
"client-id", "task-executor"
|
||||
};
|
||||
@@ -103,11 +103,6 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateId() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateIdAsFallback() {
|
||||
return true;
|
||||
@@ -163,7 +158,7 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
|
||||
String destinationName = element.getAttribute(destinationNameAttribute);
|
||||
boolean hasDestination = StringUtils.hasText(destination);
|
||||
boolean hasDestinationName = StringUtils.hasText(destinationName);
|
||||
if (!(hasDestination ^ hasDestinationName)) {
|
||||
if (hasDestination == hasDestinationName) {
|
||||
parserContext.getReaderContext().error(
|
||||
"Exactly one of '" + destinationAttribute +
|
||||
"' or '" + destinationNameAttribute + "' is required.", element);
|
||||
@@ -178,11 +173,6 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, pubSubDomainAttribute, "pubSubDomain");
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(element.getAttribute("subscription-name"))
|
||||
&& StringUtils.hasText(element.getAttribute("durable-subscription-name"))) {
|
||||
parserContext.getReaderContext().error(
|
||||
"Only one of 'subscription-name' or 'durable-subscription-name' is allowed.", element);
|
||||
}
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "destination-resolver");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "transaction-manager");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "task-executor");
|
||||
@@ -196,12 +186,9 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "idle-task-execution-limit");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "cache-level");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "subscription-durable");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "durable-subscription-name",
|
||||
"subscriptionName");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "subscription-shared");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "subscription-name");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "client-id");
|
||||
builder.addPropertyValue("autoStartup", false);
|
||||
String beanName = adapterBeanNameRoot(element, parserContext, adapterBeanDefinition)
|
||||
+ ".container";
|
||||
parserContext.getRegistry().registerBeanDefinition(beanName, builder.getBeanDefinition());
|
||||
|
||||
@@ -1525,7 +1525,7 @@
|
||||
<xsd:attribute name="recovery-interval" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Interval in miliseconds between the recovery attempts
|
||||
Interval in milliseconds between the recovery attempts
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
@@ -1368,6 +1368,12 @@ Class `org.springframework.amqp.support.AmqpHeaders` identifies the default head
|
||||
|
||||
* amqp_returnRoutingKey
|
||||
|
||||
* amqp_channel
|
||||
|
||||
* amqp_consumerTag
|
||||
|
||||
* amqp_consumerQueue
|
||||
|
||||
CAUTION: As mentioned above, using a header mapping pattern `*` is a common way to copy all headers.
|
||||
However, this can have some unexpected side-effects because certain RabbitMQ proprietary properties/headers will be
|
||||
copied as well.
|
||||
@@ -1401,7 +1407,7 @@ IMPORTANT: If you have a user defined header that begins with `!` that you *do*
|
||||
|
||||
To experiment with the AMQP adapters, check out the samples available in the Spring Integration Samples Git repository at:
|
||||
|
||||
* https://github.com/SpringSource/spring-integration-samples[https://github.com/SpringSource/spring-integration-samples]
|
||||
* https://github.com/spring-projects/spring-integration-samples[https://github.com/SpringSource/spring-integration-samples]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ This is also defined as a constant:
|
||||
IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME
|
||||
----
|
||||
|
||||
By default Spring Integration relies on an instance of ThreadPoolTaskScheduler as described in the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html[Task Execution and Scheduling] section of the Spring Framework reference manual.
|
||||
By default Spring Integration relies on an instance of `ThreadPoolTaskScheduler` as described in the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html[Task Execution and Scheduling] section of the Spring Framework reference manual.
|
||||
That default TaskScheduler will startup automatically with a pool of 10 threads, but see <<global-properties>>.
|
||||
If you provide your own TaskScheduler instance instead, you can set the 'autoStartup' property to _false_, and/or you can provide your own pool size value.
|
||||
|
||||
@@ -205,7 +205,6 @@ spring.integration.channels.maxUnicastSubscribers=0x7fffffff <2>
|
||||
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>
|
||||
----
|
||||
|
||||
<1> When true, `input-channel` s will be automatically declared as `DirectChannel` s when not explicitly found in the
|
||||
@@ -224,15 +223,9 @@ This can be overridden on individual channels with the `max-subscribers` attribu
|
||||
<5> When `true`, messages that arrive at a gateway reply channel will throw an exception, when the gateway is not
|
||||
expecting a reply - because the sending thread has timed out, or already received a reply.
|
||||
|
||||
<6> When `true`, Messaging Annotation Support (<<annotations>>) requires a declaration of the
|
||||
`@MessageEndpoint` (or any other `@Component`) annotation on the class level.
|
||||
|
||||
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.
|
||||
|
||||
NOTE: In versions prior to _4.3_, these property names had a typographical error (`...integraton...`); they have now been
|
||||
corrected (`...integration...`).
|
||||
|
||||
[[annotations]]
|
||||
=== Annotation Support
|
||||
|
||||
@@ -304,7 +297,7 @@ public class FooService {
|
||||
}
|
||||
----
|
||||
|
||||
There is also a @Headers annotation that provides all of the Message headers as a Map:
|
||||
There is also a `@Headers` annotation that provides all of the Message headers as a Map:
|
||||
[source,java]
|
||||
----
|
||||
public class FooService {
|
||||
@@ -365,18 +358,17 @@ Starting with _version 4.0_, the `@Poller` annotation has been introduced to all
|
||||
----
|
||||
public class AnnotationService {
|
||||
|
||||
@Transformer(inputChannel = "input", outputChannel = "output",
|
||||
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.fixedDelay}"))
|
||||
public String handle(String payload) {
|
||||
...
|
||||
}
|
||||
@Transformer(inputChannel = "input", outputChannel = "output",
|
||||
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.fixedDelay}"))
|
||||
public String handle(String payload) {
|
||||
...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
This annotation provides only simple `PollerMetadata` options.
|
||||
The `@Poller`'s attributes `maxMessagesPerPoll`, `fixedDelay`, `fixedRate` and `cron` can be configured with _property-placeholder_s.
|
||||
If it is necessary to provide more polling options (e.g.
|
||||
transaction, advice-chain, error-handler), the`PollerMetadata` should be configured as a generic bean with its bean name used for `@Poller`'s `value` attribute.
|
||||
The `@Poller`'s attributes `maxMessagesPerPoll`, `fixedDelay`, `fixedRate` and `cron` can be configured with _property-placeholders_.
|
||||
If it is necessary to provide more polling options (e.g. transaction, advice-chain, error-handler), the `PollerMetadata` should be configured as a generic bean with its bean name used for `@Poller`'s `value` attribute.
|
||||
In this case, no other attributes are allowed (they would be specified on the `PollerMetadata` bean).
|
||||
Note, if `inputChannel` is `PollableChannel` and no `@Poller` is configured, the default `PollerMetadata` will be used, if it is present in the application context.
|
||||
To declare the default poller using `@Configuration`, use:
|
||||
@@ -384,9 +376,9 @@ To declare the default poller using `@Configuration`, use:
|
||||
----
|
||||
@Bean(name = PollerMetadata.DEFAULT_POLLER)
|
||||
public PollerMetadata defaultPoller() {
|
||||
PollerMetadata pollerMetadata = new PollerMetadata();
|
||||
pollerMetadata.setTrigger(new PeriodicTrigger(10));
|
||||
return pollerMetadata;
|
||||
PollerMetadata pollerMetadata = new PollerMetadata();
|
||||
pollerMetadata.setTrigger(new PeriodicTrigger(10));
|
||||
return pollerMetadata;
|
||||
}
|
||||
----
|
||||
|
||||
@@ -395,10 +387,10 @@ With this endpoint using the default poller:
|
||||
----
|
||||
public class AnnotationService {
|
||||
|
||||
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output")
|
||||
public String handle(String payload) {
|
||||
...
|
||||
}
|
||||
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output")
|
||||
public String handle(String payload) {
|
||||
...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
@@ -407,9 +399,9 @@ To use a named poller, use:
|
||||
----
|
||||
@Bean
|
||||
public PollerMetadata myPoller() {
|
||||
PollerMetadata pollerMetadata = new PollerMetadata();
|
||||
pollerMetadata.setTrigger(new PeriodicTrigger(1000));
|
||||
return pollerMetadata;
|
||||
PollerMetadata pollerMetadata = new PollerMetadata();
|
||||
pollerMetadata.setTrigger(new PeriodicTrigger(1000));
|
||||
return pollerMetadata;
|
||||
}
|
||||
----
|
||||
|
||||
@@ -418,11 +410,11 @@ With this endpoint using the default poller:
|
||||
----
|
||||
public class AnnotationService {
|
||||
|
||||
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output"
|
||||
poller = @Poller("myPoller")
|
||||
public String handle(String payload) {
|
||||
...
|
||||
}
|
||||
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output"
|
||||
poller = @Poller("myPoller")
|
||||
public String handle(String payload) {
|
||||
...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
@@ -438,12 +430,12 @@ If there is need to provide some `MessageHeaders`, use a `Message<?>` return typ
|
||||
----
|
||||
@InboundChannelAdapter("counterChannel")
|
||||
public Integer count() {
|
||||
return this.counter.incrementAndGet();
|
||||
return this.counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@InboundChannelAdapter(value = "fooChannel", poller = @Poller(fixed-rate = "5000"))
|
||||
public String foo() {
|
||||
return "foo";
|
||||
return "foo";
|
||||
}
|
||||
----
|
||||
|
||||
@@ -487,7 +479,7 @@ In addition, meta-annotations can be configured hierarchically:
|
||||
@ServiceActivator(inputChannel = "annInput", outputChannel = "annOutput")
|
||||
public @interface MyServiceActivator {
|
||||
|
||||
String[] adviceChain = { "annAdvice" };
|
||||
String[] adviceChain = { "annAdvice" };
|
||||
}
|
||||
|
||||
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
|
||||
@@ -495,9 +487,9 @@ public @interface MyServiceActivator {
|
||||
@MyServiceActivator
|
||||
public @interface MyServiceActivator1 {
|
||||
|
||||
String inputChannel();
|
||||
String inputChannel();
|
||||
|
||||
String outputChannel();
|
||||
String outputChannel();
|
||||
}
|
||||
...
|
||||
|
||||
@@ -521,32 +513,32 @@ It is useful when `@Bean` definitions are "out of the box" `MessageHandler` s (`
|
||||
@EnableIntegration
|
||||
public class MyFlowConfiguration {
|
||||
|
||||
@Bean
|
||||
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
|
||||
public MessageSource<String> consoleSource() {
|
||||
return CharacterStreamReadingMessageSource.stdin();
|
||||
}
|
||||
@Bean
|
||||
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
|
||||
public MessageSource<String> consoleSource() {
|
||||
return CharacterStreamReadingMessageSource.stdin();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Transformer(inputChannel = "inputChannel", outputChannel = "httpChannel")
|
||||
public ObjectToMapTransformer toMapTransformer() {
|
||||
return new ObjectToMapTransformer();
|
||||
}
|
||||
@Bean
|
||||
@Transformer(inputChannel = "inputChannel", outputChannel = "httpChannel")
|
||||
public ObjectToMapTransformer toMapTransformer() {
|
||||
return new ObjectToMapTransformer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "httpChannel")
|
||||
public MessageHandler httpHandler() {
|
||||
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("http://foo/service");
|
||||
handler.setExpectedResponseType(String.class);
|
||||
handler.setOutputChannelName("outputChannel");
|
||||
return handler;
|
||||
}
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "httpChannel")
|
||||
public MessageHandler httpHandler() {
|
||||
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("http://foo/service");
|
||||
handler.setExpectedResponseType(String.class);
|
||||
handler.setOutputChannelName("outputChannel");
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "outputChannel")
|
||||
public LoggingHandler loggingHandler() {
|
||||
return new LoggingHandler("info");
|
||||
}
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "outputChannel")
|
||||
public LoggingHandler loggingHandler() {
|
||||
return new LoggingHandler("info");
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
@@ -578,7 +570,7 @@ method level, meaning to skip the bean registration by some condition reason:
|
||||
@ServiceActivator(inputChannel = "skippedChannel")
|
||||
@Profile("foo")
|
||||
public MessageHandler skipped() {
|
||||
return System.out::println;
|
||||
return System.out::println;
|
||||
}
|
||||
----
|
||||
Together with the existing Spring Container logic, the Messaging Endpoint bean, based on the `@ServiceActivator`
|
||||
@@ -592,23 +584,23 @@ This is just for completeness, providing a convenient mechanism to declare a`Bri
|
||||
----
|
||||
@Bean
|
||||
public PollableChannel bridgeFromInput() {
|
||||
return new QueueChannel();
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@BridgeFrom(value = "bridgeFromInput", poller = @Poller(fixedDelay = "1000"))
|
||||
public MessageChannel bridgeFromOutput() {
|
||||
return new DirectChannel();
|
||||
return new DirectChannel();
|
||||
}
|
||||
@Bean
|
||||
public QueueChannel bridgeToOutput() {
|
||||
return new QueueChannel();
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@BridgeTo("bridgeToOutput")
|
||||
public MessageChannel bridgeToInput() {
|
||||
return new DirectChannel();
|
||||
return new DirectChannel();
|
||||
}
|
||||
----
|
||||
|
||||
@@ -770,7 +762,8 @@ The payload is not being mapped to any argument.
|
||||
_Multiple parameters:_
|
||||
|
||||
Multiple parameters could create a lot of ambiguity with regards to determining the appropriate mappings.
|
||||
The general advice is to annotate your method parameters with @Payload and/or @Header/@Headers Below are some of the examples of ambiguous conditions which result in an Exception being raised.
|
||||
The general advice is to annotate your method parameters with `@Payload` and/or `@Header`/`@Headers`.
|
||||
Below are some of the examples of ambiguous conditions which result in an Exception being raised.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@@ -805,9 +798,9 @@ _Multiple methods (same or different name) with legal (mappable) signatures:_
|
||||
[source,java]
|
||||
----
|
||||
public class Foo {
|
||||
public String foo(String str, Map m);
|
||||
public String foo(String str, Map m);
|
||||
|
||||
public String foo(Map m);
|
||||
public String foo(Map m);
|
||||
}
|
||||
----
|
||||
|
||||
@@ -819,7 +812,7 @@ To make meters worse both methods have the same name which at first might look v
|
||||
[source,xml]
|
||||
----
|
||||
<int:service-activator input-channel="input" output-channel="output" method="foo">
|
||||
<bean class="org.bar.Foo"/>
|
||||
<bean class="org.bar.Foo"/>
|
||||
</int:service-activator>
|
||||
----
|
||||
|
||||
@@ -831,9 +824,9 @@ On the other hand let's look at slightly different example:
|
||||
[source,java]
|
||||
----
|
||||
public class Foo {
|
||||
public String foo(String str, Map m);
|
||||
public String foo(String str, Map m);
|
||||
|
||||
public String foo(String str);
|
||||
public String foo(String str);
|
||||
}
|
||||
----
|
||||
|
||||
@@ -846,16 +839,16 @@ However if the method names were different you could influence the mapping with
|
||||
[source,java]
|
||||
----
|
||||
public class Foo {
|
||||
public String foo(String str, Map m);
|
||||
public String foo(String str, Map m);
|
||||
|
||||
public String bar(String str);
|
||||
public String bar(String str);
|
||||
}
|
||||
----
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<int:service-activator input-channel="input" output-channel="output" method="bar">
|
||||
<bean class="org.bar.Foo"/>
|
||||
<bean class="org.bar.Foo"/>
|
||||
</int:service-activator>
|
||||
----
|
||||
|
||||
|
||||
Reference in New Issue
Block a user