diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.1.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.1.xsd
index 6e77bd235a..bde78fa5f9 100644
--- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.1.xsd
+++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.1.xsd
@@ -4352,10 +4352,11 @@ The list of component name patterns you want to track (e.g., tracked-components
- The 'MetadataStore' reference. Used by the underlying
+ A 'ConcurrentMetadataStore' reference. Used by the underlying
'org.springframework.integration.selector.MetadataStoreSelector'.
Mutually exclusive with 'selector'.
- Optional. By default 'MetadataStoreSelector' uses an internal 'SimpleMetadataStore'.
+ Optional. The default 'MetadataStoreSelector' uses an internal 'SimpleMetadataStore' which
+ does not maintain state across application executions.
diff --git a/src/reference/docbook/aggregator.xml b/src/reference/docbook/aggregator.xml
index db788a6bd6..16b444ff9a 100644
--- a/src/reference/docbook/aggregator.xml
+++ b/src/reference/docbook/aggregator.xml
@@ -398,7 +398,7 @@ then you should simply provide an implementation of the ReleaseStrate
The id of the aggregator is
- 0ptional.
+ Optional.
diff --git a/src/reference/docbook/handler-advice.xml b/src/reference/docbook/handler-advice.xml
index 232feb7f73..108d489104 100644
--- a/src/reference/docbook/handler-advice.xml
+++ b/src/reference/docbook/handler-advice.xml
@@ -583,9 +583,144 @@ public class MyAdvisedFilter {
- Idempotent Receiver EIP Pattern
+ Idempotent Receiver Enterprise Integration Pattern
- TBD
+ Starting with version 4.1, Spring Integration provides an implementation
+ of the Idempotent Receiver
+ Enterprise Integration Pattern. It is a functional pattern and the whole
+ idempotency logic should be implemented in the application, however to simplify the
+ decision-making, the IdempotentReceiverInterceptor component is provided. This is
+ an AOP Advice, which is applied to the
+ MessageHandler.handleMessage() method and can filter a request message or mark it as
+ a duplicate, according to its configuration.
+
+ Previously, users could have implemented this pattern,
+ by using a custom MessageSelector in a <filter/> (), for example.
+ However, since this pattern is really behavior of an endpoint rather than being an endpoint itself,
+ the Idempotent Receiver implementation doesn't provide an endpoint component; rather,
+ it is applied to endpoints declared in the application.
+
+
+ The logic of the IdempotentReceiverInterceptor is based on the provided
+ MessageSelector and, if the message isn't accepted by that selector, it
+ will be enriched with the duplicateMessage header set to true. The target
+ MessageHandler (or downstream flow) can consult this header to implement the
+ correct idempotency logic. If the IdempotentReceiverInterceptor
+ is configured with a discardChannel and/or throwExceptionOnRejection = true, the
+ duplicate Message won't be sent to the target
+ MessageHandler.handleMessage(), but discarded. If you simply want to discard (do nothing with)
+ the duplicate Message, the discardChannel should be configured with a
+ NullChannel, such as the default nullChannel bean.
+
+
+ To maintain state between messages and provide the ability to compare messages for the
+ idempotency, the MetadataStoreSelector is provided. It accepts a
+ MetadataKeyStrategy implementation (which creates a lookup key
+ based on the Message) and an optional
+ ConcurrentMetadataStore ().
+ See the MetadataStoreSelector JavaDocs for more information. An
+ ExpressionMetadataKeyStrategy implementation is provided, allowing
+ simple SpEL expressions to be used to determine the key from the message.
+
+
+ For convenience, the MetadataStoreSelector options are configurable directly on
+ the <idempotent-receiver> component:
+
+ ]]>
+
+
+ The id of the IdempotentReceiverInterceptor bean.
+ Optional.
+
+
+
+
+ Consumer Endpoint name(s) or pattern(s) to which this interceptor will be applied.
+ Separate names (patterns) with commas (,)
+ e.g. endpoint="aaa, bbb*, *ccc, *ddd*, eee*fff".
+ Endpoint bean names matching these patterns are then used to retrieve the target endpoint's
+ MessageHandler bean (using its .handler suffix),
+ and the IdempotentReceiverInterceptor will be applied to those beans.
+ Required.
+
+
+
+
+ A MessageSelector bean reference.
+ Mutually exclusive with metadata-store and
+ key-strategy (key-expression).
+
+
+
+
+
+ Identifies the channel to which to send a message when the IdempotentReceiverInterceptor
+ doesn't accept it. When omitted, duplicate messages are forwarded to the handler with a
+ duplicateMessage header. Optional.
+
+
+
+
+ A ConcurrentMetadataStore reference. Used by the underlying
+ MetadataStoreSelector. Mutually exclusive with selector.
+ Optional.
+ The default MetadataStoreSelector uses an internal
+ SimpleMetadataStore which does not maintain state across
+ application executions.
+
+
+
+
+ A MetadataKeyStrategy reference. Used by the underlying
+ MetadataStoreSelector.
+ Evaluates an idempotentKey from the request Message.
+ Mutually exclusive with selector and key-expression.
+
+
+
+
+
+ A SpEL expression to populate an ExpressionMetadataKeyStrategy.
+ Used by the underlying MetadataStoreSelector.
+ Evaluates an idempotentKey using the request Message as the evaluation context root object.
+ Mutually exclusive with selector and key-strategy.
+
+
+
+
+
+ Throw an exception if the IdempotentReceiverInterceptor rejects the message
+ defaults to false.
+ It is applied regardless of whether or not a discard-channel is provided.
+
+
+
+
+ For Java configuration, the method level IdempotentReceiver annotation is provided. It
+ is used to mark a @Bean that has a Messaging annotation (@ServiceActivator,
+ @Router etc.) to specify which IdempotentReceiverInterceptors will be
+ applied to this endpoint:
+
+
+ m.getHeaders().get(INVOICE_NBR_HEADER)));
+}
+
+@Bean
+@ServiceActivator(inputChannel = "input", outputChannel = "output")
+@IdempotentReceiver("idempotentReceiverInterceptor")
+public MessageHandler myService() {
+ ....
+}]]>