From 868004e9e4194f59820427fe1db3d44fbb67596c Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Wed, 31 Aug 2016 11:53:52 -0400 Subject: [PATCH] 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 --- .../config/IntegrationRegistrar.java | 3 - .../MessagingAnnotationPostProcessor.java | 119 ++++++--------- .../context/IntegrationProperties.java | 10 -- .../gateway/GatewayProxyFactoryBean.java | 12 +- .../spring.integration.default.properties | 2 - ...notatedEndpointActivationTests-context.xml | 4 - .../AnnotatedEndpointActivationTests.java | 3 +- .../gateway/GatewayProxyFactoryBeanTests.java | 43 ------ .../JmsMessageDrivenEndpointParser.java | 19 +-- .../jms/config/spring-integration-jms-5.0.xsd | 2 +- src/reference/asciidoc/amqp.adoc | 8 +- src/reference/asciidoc/configuration.adoc | 141 +++++++++--------- 12 files changed, 128 insertions(+), 238 deletions(-) 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 b48cf7b6ed..943152a205 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 @@ -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, diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java index aedf96f5b3..9814feaa71 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java @@ -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, List> annotationChains = - new HashMap, List>(); - for (Class annotationType : - MessagingAnnotationPostProcessor.this.postProcessors.keySet()) { - if (AnnotatedElementUtils.isAnnotated(method, annotationType.getName())) { - List annotationChain = getAnnotationChain(method, annotationType); - if (annotationChain.size() > 0) { - annotationChains.put(annotationType, annotationChain); - } + ReflectionUtils.doWithMethods(beanClass, method -> { + Map, List> annotationChains = new HashMap<>(); + for (Class annotationType : + MessagingAnnotationPostProcessor.this.postProcessors.keySet()) { + if (AnnotatedElementUtils.isAnnotated(method, annotationType.getName())) { + List annotationChain = getAnnotationChain(method, annotationType); + if (annotationChain.size() > 0) { + annotationChains.put(annotationType, annotationChain); } } + } - for (Map.Entry, List> entry : annotationChains.entrySet()) { - Class annotationType = entry.getKey(); - List 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, List> entry : annotationChains.entrySet()) { + Class annotationType = entry.getKey(); + List 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); } } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java index dfdad45153..11c209e424 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationProperties.java @@ -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 { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java index acce1e9536..2969959e67 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java @@ -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(); } diff --git a/spring-integration-core/src/main/resources/META-INF/spring.integration.default.properties b/spring-integration-core/src/main/resources/META-INF/spring.integration.default.properties index b433a27493..5c6bfd8b16 100644 --- a/spring-integration-core/src/main/resources/META-INF/spring.integration.default.properties +++ b/spring-integration-core/src/main/resources/META-INF/spring.integration.default.properties @@ -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 diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/AnnotatedEndpointActivationTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/AnnotatedEndpointActivationTests-context.xml index 45b0cf167a..2033bcf5ab 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/AnnotatedEndpointActivationTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/AnnotatedEndpointActivationTests-context.xml @@ -13,10 +13,6 @@ - - true - - diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/AnnotatedEndpointActivationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/AnnotatedEndpointActivationTests.java index b3ea565f8a..c8e715a0b9 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/AnnotatedEndpointActivationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/AnnotatedEndpointActivationTests.java @@ -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 diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java index 4c1e203e18..4f57dfa8e0 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayProxyFactoryBeanTests.java @@ -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(); diff --git a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsMessageDrivenEndpointParser.java b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsMessageDrivenEndpointParser.java index 60edf9eb67..5c7f234a4a 100644 --- a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsMessageDrivenEndpointParser.java +++ b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsMessageDrivenEndpointParser.java @@ -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()); diff --git a/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-5.0.xsd b/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-5.0.xsd index 362daca3bf..b70340ddad 100644 --- a/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-5.0.xsd +++ b/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-5.0.xsd @@ -1525,7 +1525,7 @@ - Interval in miliseconds between the recovery attempts + Interval in milliseconds between the recovery attempts diff --git a/src/reference/asciidoc/amqp.adoc b/src/reference/asciidoc/amqp.adoc index 5b3e7376c1..4a135519a1 100644 --- a/src/reference/asciidoc/amqp.adoc +++ b/src/reference/asciidoc/amqp.adoc @@ -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] diff --git a/src/reference/asciidoc/configuration.adoc b/src/reference/asciidoc/configuration.adoc index 3e0cc5f7a2..3fe2a85f7c 100644 --- a/src/reference/asciidoc/configuration.adoc +++ b/src/reference/asciidoc/configuration.adoc @@ -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 <>. 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 (<>) 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 consoleSource() { - return CharacterStreamReadingMessageSource.stdin(); - } + @Bean + @InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000")) + public MessageSource 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] ---- - + ---- @@ -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] ---- - + ----