From f3bf2a68d6ac2ee519ea187b062a2a7640309970 Mon Sep 17 00:00:00 2001 From: Jay Bryant Date: Thu, 28 Jun 2018 13:43:24 -0500 Subject: [PATCH] Full editing pass for the Reference Guide I went through all the Asciidoc files to correct spelling, grammar, punctuation, and usage. Wherever possible, I also made it more clear and more concise. I also added links wherever they were reasonable. Accommodating changes that came while I was editing Various folks made changes (one of which I recommended) to the documents while I spent a month editing. I had to edit that new and changed content as well, so I need this second commit. Accommodating Artem's requested changes for `aggregator.adoc` Artem reviewed `aggregator.adoc` as a starting point, so that he could get some questions answered. I have made the changes he requested (and answered his questions on Github). --- src/reference/asciidoc/aggregator.adoc | 724 ++++---- src/reference/asciidoc/amqp.adoc | 1332 +++++++-------- src/reference/asciidoc/barrier.adoc | 48 +- src/reference/asciidoc/bridge.adoc | 58 +- src/reference/asciidoc/chain.adoc | 149 +- src/reference/asciidoc/changes-1.0-2.0.adoc | 140 +- src/reference/asciidoc/changes-2.0-2.1.adoc | 144 +- src/reference/asciidoc/changes-2.1-2.2.adoc | 161 +- src/reference/asciidoc/changes-2.2-3.0.adoc | 367 +++-- src/reference/asciidoc/changes-3.0-4.0.adoc | 235 +-- src/reference/asciidoc/changes-4.0-4.1.adoc | 172 +- src/reference/asciidoc/changes-4.1-4.2.adoc | 298 ++-- src/reference/asciidoc/changes-4.2-4.3.adoc | 276 ++-- src/reference/asciidoc/changes-4.3-5.0.adoc | 271 ++- src/reference/asciidoc/channel-adapter.adoc | 116 +- src/reference/asciidoc/channel.adoc | 689 ++++---- src/reference/asciidoc/claim-check.adoc | 226 ++- src/reference/asciidoc/codec.adoc | 101 +- src/reference/asciidoc/configuration.adoc | 782 +++++---- .../asciidoc/content-enrichment.adoc | 333 ++-- src/reference/asciidoc/control-bus.adoc | 40 +- src/reference/asciidoc/delayer.adoc | 148 +- src/reference/asciidoc/dsl.adoc | 557 ++++--- src/reference/asciidoc/endpoint-summary.adoc | 448 +---- src/reference/asciidoc/endpoint.adoc | 647 ++++---- src/reference/asciidoc/event.adoc | 55 +- src/reference/asciidoc/feed.adoc | 71 +- src/reference/asciidoc/file.adoc | 829 +++++----- src/reference/asciidoc/filter.adoc | 136 +- src/reference/asciidoc/ftp.adoc | 823 +++++---- src/reference/asciidoc/gateway.adoc | 606 ++++--- src/reference/asciidoc/gemfire.adoc | 168 +- src/reference/asciidoc/graph.adoc | 132 +- src/reference/asciidoc/groovy.adoc | 128 +- src/reference/asciidoc/handler-advice.adoc | 481 +++--- src/reference/asciidoc/http.adoc | 670 ++++---- src/reference/asciidoc/images/epub-cover.png | Bin 0 -> 75904 bytes src/reference/asciidoc/images/epub-cover.svg | 14 + src/reference/asciidoc/index.adoc | 47 +- src/reference/asciidoc/ip.adoc | 1466 ++++++++++------- src/reference/asciidoc/jdbc.adoc | 878 +++++----- src/reference/asciidoc/jms.adoc | 778 ++++----- src/reference/asciidoc/jmx.adoc | 369 +++-- src/reference/asciidoc/jpa.adoc | 983 ++++++----- src/reference/asciidoc/logging-adapter.adoc | 48 +- src/reference/asciidoc/mail.adoc | 407 +++-- .../asciidoc/message-construction.adoc | 4 - src/reference/asciidoc/message-history.adoc | 59 +- .../asciidoc/message-publishing.adoc | 241 +-- src/reference/asciidoc/message-routing.adoc | 2 + src/reference/asciidoc/message-store.adoc | 132 +- src/reference/asciidoc/message.adoc | 440 ++--- src/reference/asciidoc/meta-data-store.adoc | 53 +- src/reference/asciidoc/metrics.adoc | 283 ++-- src/reference/asciidoc/mongodb.adoc | 271 +-- src/reference/asciidoc/mqtt.adoc | 194 ++- src/reference/asciidoc/overview.adoc | 590 +++---- src/reference/asciidoc/polling-consumer.adoc | 169 +- src/reference/asciidoc/preface.adoc | 40 +- src/reference/asciidoc/redis.adoc | 740 ++++----- src/reference/asciidoc/resequencer.adoc | 154 +- src/reference/asciidoc/resources.adoc | 3 - src/reference/asciidoc/rmi.adoc | 54 +- src/reference/asciidoc/router.adoc | 870 +++++----- src/reference/asciidoc/samples.adoc | 414 +++-- src/reference/asciidoc/scatter-gather.adoc | 175 +- src/reference/asciidoc/scripting.adoc | 136 +- src/reference/asciidoc/security.adoc | 129 +- src/reference/asciidoc/service-activator.adoc | 152 +- src/reference/asciidoc/sftp.adoc | 876 +++++----- src/reference/asciidoc/shutdown.adoc | 53 +- src/reference/asciidoc/spel.adoc | 157 +- src/reference/asciidoc/splitter.adoc | 130 +- src/reference/asciidoc/stomp.adoc | 275 ++-- src/reference/asciidoc/stream.adoc | 87 +- src/reference/asciidoc/syslog.adoc | 83 +- src/reference/asciidoc/testing.adoc | 180 +- src/reference/asciidoc/transactions.adoc | 206 ++- src/reference/asciidoc/transformer.adoc | 383 +++-- src/reference/asciidoc/twitter.adoc | 287 ++-- src/reference/asciidoc/web-sockets.adoc | 443 +++-- src/reference/asciidoc/webflux.adoc | 108 +- src/reference/asciidoc/whats-new.adoc | 84 +- src/reference/asciidoc/ws.adoc | 218 ++- src/reference/asciidoc/xml.adoc | 819 ++++----- src/reference/asciidoc/xmpp.adoc | 326 ++-- src/reference/asciidoc/zookeeper.adoc | 56 +- 87 files changed, 14163 insertions(+), 13464 deletions(-) create mode 100644 src/reference/asciidoc/images/epub-cover.png create mode 100644 src/reference/asciidoc/images/epub-cover.svg delete mode 100644 src/reference/asciidoc/message-construction.adoc diff --git a/src/reference/asciidoc/aggregator.adoc b/src/reference/asciidoc/aggregator.adoc index 46ad598e89..37a27ca7bb 100644 --- a/src/reference/asciidoc/aggregator.adoc +++ b/src/reference/asciidoc/aggregator.adoc @@ -1,67 +1,57 @@ [[aggregator]] === Aggregator -[[aggregator-introduction]] -==== Introduction +Basically a mirror-image of the splitter, the aggregator is a type of message handler that receives multiple messages and combines them into a single message. +In fact, an aggregator is often a downstream consumer in a pipeline that includes a splitter. -Basically a mirror-image of the Splitter, the Aggregator is a type of Message Handler that receives multiple Messages and combines them into a single Message. -In fact, an Aggregator is often a downstream consumer in a pipeline that includes a Splitter. - -Technically, the Aggregator is more complex than a Splitter, because it is stateful as it must hold the Messages to be aggregated and determine when the complete group of Messages is ready to be aggregated. -In order to do this it requires a `MessageStore`. +Technically, the aggregator is more complex than a splitter, because it is stateful. +It must hold the messages to be aggregated and determine when the complete group of messages is ready to be aggregated. +In order to do so, it requires a `MessageStore`. [[aggregator-functionality]] ==== Functionality -The Aggregator combines a group of related messages, by correlating and storing them, until the group is deemed complete. -At that point, the Aggregator will create a single message by processing the whole group, and will send the aggregated message as output. +The Aggregator combines a group of related messages, by correlating and storing them, until the group is deemed to be complete. +At that point, the aggregator creates a single message by processing the whole group and sends the aggregated message as output. -Implementing an Aggregator requires providing the logic to perform the aggregation (i.e., the creation of a single message from many). +Implementing an aggregator requires providing the logic to perform the aggregation (that is, the creation of a single message from many). Two related concepts are correlation and release. Correlation determines how messages are grouped for aggregation. -In Spring Integration correlation is done by default based on the `IntegrationMessageHeaderAccessor.CORRELATION_ID` message header. -Messages with the same `IntegrationMessageHeaderAccessor.CORRELATION_ID` will be grouped together. -However, the correlation strategy may be customized to allow other ways of specifying how the messages should be grouped together by implementing a `CorrelationStrategy` (see below). +In Spring Integration, correlation is done by default, based on the `IntegrationMessageHeaderAccessor.CORRELATION_ID` message header. +Messages with the same `IntegrationMessageHeaderAccessor.CORRELATION_ID` are grouped together. +However, you can customize the correlation strategy to allow other ways of specifying how the messages should be grouped together. +To do so, you can implement a `CorrelationStrategy` (covered later in this chapter). To determine the point at which a group of messages is ready to be processed, a `ReleaseStrategy` is consulted. -The default release strategy for the Aggregator will release a group when all messages included in a sequence are present, based on the `IntegrationMessageHeaderAccessor.SEQUENCE_SIZE` header. -This default strategy may be overridden by providing a reference to a custom `ReleaseStrategy` implementation. +The default release strategy for the aggregator releases a group when all messages included in a sequence are present, based on the `IntegrationMessageHeaderAccessor.SEQUENCE_SIZE` header. +You can override this default strategy by providing a reference to a custom `ReleaseStrategy` implementation. [[aggregator-api]] -==== Programming model +==== Programming Model The Aggregation API consists of a number of classes: * The interface `MessageGroupProcessor`, and its subclasses: `MethodInvokingAggregatingMessageGroupProcessor` and `ExpressionEvaluatingMessageGroupProcessor` +* The `ReleaseStrategy` interface and its default implementation: `SimpleSequenceSizeReleaseStrategy` +* The `CorrelationStrategy` interface and its default implementation: `HeaderAttributeCorrelationStrategy` -* The `ReleaseStrategy` interface and its default implementation `SimpleSequenceSizeReleaseStrategy` +===== `AggregatingMessageHandler` -* The `CorrelationStrategy` interface and its default implementation `HeaderAttributeCorrelationStrategy` +The `AggregatingMessageHandler` (a subclass of `AbstractCorrelatingMessageHandler`) is a `MessageHandler` implementation, encapsulating the common functionalities of an aggregator (and other correlating use cases), which are as follows: +* Correlating messages into a group to be aggregated +* Maintaining those messages in a `MessageStore` until the group can be released +* Deciding when the group can be released +* Aggregating the released group into a single message +* Recognizing and responding to an expired group +The responsibility for deciding how the messages should be grouped together is delegated to a `CorrelationStrategy` instance. +The responsibility for deciding whether the message group can be released is delegated to a `ReleaseStrategy` instance. -===== AggregatingMessageHandler - -The `AggregatingMessageHandler` (subclass of `AbstractCorrelatingMessageHandler`) is a `MessageHandler` implementation, encapsulating the common functionalities of an Aggregator (and other correlating use cases), which are: - -* correlating messages into a group to be aggregated - -* maintaining those messages in a `MessageStore` until the group can be released - -* deciding when the group can be released - -* aggregating the released group into a single message - -* recognizing and responding to an expired group - - - -The responsibility of deciding how the messages should be grouped together is delegated to a `CorrelationStrategy` instance. -The responsibility of deciding whether the message group can be released is delegated to a `ReleaseStrategy` instance. - -Here is a brief highlight of the base `AbstractAggregatingMessageGroupProcessor` (the responsibility of implementing the `aggregatePayloads` method is left to the developer): +The following listing shows a brief highlight of the base `AbstractAggregatingMessageGroupProcessor` (the responsibility for implementing the `aggregatePayloads` method is left to the developer): +==== [source,java] ---- public abstract class AbstractAggregatingMessageGroupProcessor @@ -75,9 +65,11 @@ public abstract class AbstractAggregatingMessageGroupProcessor } ---- +==== -The `CorrelationStrategy` is owned by the `AbstractCorrelatingMessageHandler` and it has a default value based on the `IntegrationMessageHeaderAccessor.CORRELATION_ID` message header: +The `CorrelationStrategy` is owned by the `AbstractCorrelatingMessageHandler` and has a default value based on the `IntegrationMessageHeaderAccessor.CORRELATION_ID` message header, as the following example shows: +==== [source,java] ---- public AbstractCorrelatingMessageHandler(MessageGroupProcessor processor, MessageGroupStore store, @@ -89,66 +81,54 @@ public AbstractCorrelatingMessageHandler(MessageGroupProcessor processor, Messag ... } ---- +==== -As for actual processing of the message group, the default implementation is the `DefaultAggregatingMessageGroupProcessor`. -It creates a single Message whose payload is a List of the payloads received for a given group. -This works well for simple Scatter Gather implementations with either a Splitter, Publish Subscribe Channel, or Recipient List Router upstream. +As for the actual processing of the message group, the default implementation is the `DefaultAggregatingMessageGroupProcessor`. +It creates a single `Message` whose payload is a `List` of the payloads received for a given group. +This works well for simple scatter-gather implementations with a splitter, a publish-subscribe channel, or a recipient list router upstream. -NOTE: When using a Publish Subscribe Channel or Recipient List Router in this type of scenario, be sure to enable the flag to `apply-sequence`. -That will add the necessary headers (`CORRELATION_ID`, `SEQUENCE_NUMBER` and `SEQUENCE_SIZE`). -That behavior is enabled by default for Splitters in Spring Integration, but it is not enabled for the Publish Subscribe Channel or Recipient List Router because those components may be used in a variety of contexts in which these headers are not necessary. +NOTE: When using a publish-subscribe channel or a recipient list router in this type of scenario, be sure to enable the `apply-sequence` flag. +Doing so adds the necessary headers: `CORRELATION_ID`, `SEQUENCE_NUMBER`, and `SEQUENCE_SIZE`. +That behavior is enabled by default for splitters in Spring Integration, but it is not enabled for publish-subscribe channels or for recipient list routers because those components may be used in a variety of contexts in which these headers are not necessary. -When implementing a specific aggregator strategy for an application, a developer can extend `AbstractAggregatingMessageGroupProcessor` and implement the `aggregatePayloads` method. -However, there are better solutions, less coupled to the API, for implementing the aggregation logic which can be configured easily either through XML or through annotations. +When implementing a specific aggregator strategy for an application, you can extend `AbstractAggregatingMessageGroupProcessor` and implement the `aggregatePayloads` method. +However, there are better solutions, less coupled to the API, for implementing the aggregation logic, which can be configured either through XML or through annotations. In general, any POJO can implement the aggregation algorithm if it provides a method that accepts a single `java.util.List` as an argument (parameterized lists are supported as well). -This method will be invoked for aggregating messages as follows: +This method is invoked for aggregating messages as follows: -* if the argument is a `java.util.Collection`, and the parameter type T is assignable to `Message`, -then the whole list of messages accumulated for aggregation will be sent to the aggregator +* If the argument is a `java.util.Collection`, and the parameter type T is assignable to `Message`, the whole list of messages accumulated for aggregation is sent to the aggregator. +* If the argument is a non-parameterized `java.util.Collection` or the parameter type is not assignable to `Message`, the method receives the payloads of the accumulated messages. +* If the return type is not assignable to `Message`, it is treated as the payload for a `Message` that is automatically created by the framework. -* if the argument is a non-parameterized `java.util.Collection` or the parameter type is not assignable to `Message`, -then the method will receive the payloads of the accumulated messages - -* if the return type is not assignable to `Message`, then it will be treated as the payload for a Message that will be created automatically by the framework. - - - -NOTE: In the interest of code simplicity, and promoting best practices such as low coupling, testability, etc., the preferred way of implementing the aggregation logic is through a POJO, and using the XML or annotation support for configuring it in the application. +NOTE: In the interest of code simplicity and promoting best practices such as low coupling, testability, and others, the preferred way of implementing the aggregation logic is through a POJO and using the XML or annotation support for configuring it in the application. [[agg-message-collection]] -IMPORTANT: The `SimpleMessageGroup.getMessages()` method returns an `unmodifiableCollection`, therefore, -if your aggregating POJO method has a `Collection` parameter, the argument passed in will be exactly that -`Collection` instance and, when a `SimpleMessageStore` is used for the Aggregator, -that original `Collection` will be cleared after releasing the group. -Hence the `Collection` variable in the POJO will be cleared too, if passed out of the aggregator. -If you wish to simply release that collection as-is for further processing, -it is required that you build a new `Collection` (e.g. `new ArrayList(messages)`) -Starting with _version 4.3, the Framework no longer copies the messages to a new collection, to avoid undesired extra -object creation. +IMPORTANT: The `SimpleMessageGroup.getMessages()` method returns an `unmodifiableCollection`. +Therefore, if your aggregating POJO method has a `Collection` parameter, the argument passed in is exactly that `Collection` instance and, when you use a `SimpleMessageStore` for the aggregator, that original `Collection` is cleared after releasing the group. +Consequently, the `Collection` variable in the POJO is cleared too, if it is passed out of the aggregator. +If you wish to simply release that collection as-is for further processing, you must build a new `Collection` (for example, `new ArrayList(messages)`). +Starting with version 4.3, the framework no longer copies the messages to a new collection, to avoid undesired extra object creation. -If the `MessageGroupProcessor` 's `processMessageGroup` method returns a collection, it must be a collection of -`Message` s. -In this case, the messages are released individually. -Prior to _version 4.2_, it was not possible to provide a `MessageGroupProcessor` using XML configuration, only POJO -methods could be used for aggregation. -Now, if the framework detects that the referenced (or inner) bean implements `MessageProcessor`, it is used as the -aggregator's output processor. +If the `processMessageGroup` method of the `MessageGroupProcessor` returns a collection, it must be a collection of `Message` objects. +In this case, the messages are individually released. +Prior to version 4.2, it was not possible to provide a `MessageGroupProcessor` by using XML configuration. +Only POJO methods could be used for aggregation. +Now, if the framework detects that the referenced (or inner) bean implements `MessageProcessor`, it is used as the aggregator's output processor. -If you wish to release a collection of objects from a custom `MessageGroupProcessor` as the payload of a message, your -class should extend `AbstractAggregatingMessageGroupProcessor` and implement `aggregatePayloads()`. +If you wish to release a collection of objects from a custom `MessageGroupProcessor` as the payload of a message, your class should extend `AbstractAggregatingMessageGroupProcessor` and implement `aggregatePayloads()`. -Also, since _version 4.2_, a `SimpleMessageGroupProcessor` is provided; which simply returns the collection of -messages from the group, which, as indicated above, causes the released messages to be sent individually. +Also, since version 4.2, a `SimpleMessageGroupProcessor` is provided. +It returns the collection of messages from the group, which, as indicated earlier, causes the released messages to be sent individually. -This allows the aggregator to work as a message barrier where arriving messages are held until the release strategy -fires, and the group is released, as a sequence of individual messages. +This lets the aggregator work as a message barrier, where arriving messages are held until the release strategy fires and the group is released as a sequence of individual messages. -===== ReleaseStrategy +===== `ReleaseStrategy` The `ReleaseStrategy` interface is defined as follows: +==== [source,java] ---- public interface ReleaseStrategy { @@ -157,17 +137,16 @@ public interface ReleaseStrategy { } ---- +==== -In general, any POJO can implement the completion decision logic if it provides a method that accepts a single `java.util.List` as an argument (parameterized lists are supported as well), and returns a boolean value. -This method will be invoked after the arrival of each new message, to decide whether the group is complete or not, as follows: +In general, any POJO can implement the completion decision logic if it provides a method that accepts a single `java.util.List` as an argument (parameterized lists are supported as well) and returns a boolean value. +This method is invoked after the arrival of each new message, to decide whether the group is complete or not, as follows: -* if the argument is a `java.util.List`, and the parameter type T is assignable to `Message`, then the whole list of messages accumulated in the group will be sent to the method +* If the argument is a `java.util.List`, and the parameter type `T` is assignable to `Message`, the whole list of messages accumulated in the group is sent to the method. +* If the argument is a non-parametrized `java.util.List` or the parameter type is not assignable to `Message`, the method receives the payloads of the accumulated messages. +* The method must return `true` if the message group is ready for aggregation or false otherwise. -* if the argument is a non-parametrized `java.util.List` or the parameter type is not assignable to `Message`, then the method will receive the payloads of the accumulated messages - -* the method must return true if the message group is ready for aggregation, and false otherwise. - -For example: +The following example shows how to use the `@ReleaseStrategy` annotation for a `List` of type `Message`: [source,java] ---- @@ -178,6 +157,8 @@ public class MyReleaseStrategy { } ---- +The following example shows how to use the `@ReleaseStrategy` annotation for a `List` of type `String`: + [source,java] ---- public class MyReleaseStrategy { @@ -187,39 +168,40 @@ public class MyReleaseStrategy { } ---- -As you can see based on the above signatures, the POJO-based Release Strategy will be passed a `Collection` of not-yet-released Messages (if you need access to the whole `Message`) or a `Collection` of payload objects (if the type parameter is anything other than `Message`). -Typically this would satisfy the majority of use cases. -However if, for some reason, you need to access the full `MessageGroup` then you should simply provide an implementation of the `ReleaseStrategy` interface. +Based on the signatures in the preceding two examples, the POJO-based release strategy is passed a `Collection` of not-yet-released messages (if you need access to the whole `Message`) or a `Collection` of payload objects (if the type parameter is anything other than `Message`). +This satisfies the majority of use cases. +However if, for some reason, you need to access the full `MessageGroup`, you should provide an implementation of the `ReleaseStrategy` interface. [WARNING] ===== -When handling potentially large groups, it is important to understand how these methods are invoked because the release strategy may be invoked multiple times before the group is released. -The most efficient is an implementation of `ReleaseStrategy` because the aggregator can invoke it directly. +When handling potentially large groups, you should understand how these methods are invoked, because the release strategy may be invoked multiple times before the group is released. +The most efficient is an implementation of `ReleaseStrategy`, because the aggregator can invoke it directly. The second most efficient is a POJO method with a `Collection>` parameter type. -The least efficient is a POJO method with a `Collection` type - the framework has to copy the payloads from the messages in the group into a new collection (and possibly attempt conversion on the payloads to `Foo`) every time the release strategy is called. -`Collection` avoids the conversion but still requires creating the new `Collection`. +The least efficient is a POJO method with a `Collection` type. The framework has to copy the payloads from the messages in the group into a new collection (and possibly attempt conversion on the payloads to `Something`) every time the release strategy is called. +Using `Collection` avoids the conversion but still requires creating the new `Collection`. -*For these reasons, for large groups, it is recommended that you implement `ReleaseStrategy`.* +For these reasons, for large groups, we recommended that you implement `ReleaseStrategy`. ===== When the group is released for aggregation, all its not-yet-released messages are processed and removed from the group. -If the group is also complete (i.e. -if all messages from a sequence have arrived or if there is no sequence defined), then the group is marked as complete. -Any new messages for this group will be sent to the discard channel (if defined). -Setting `expire-groups-upon-completion` to `true` (default is `false`) removes the entire group and any new messages, with the same correlation id as the removed group, will form a new group. -Partial sequences can be released by using a `MessageGroupStoreReaper` together with `send-partial-result-on-expiry` being set to `true`. +If the group is also complete (that is, if all messages from a sequence have arrived or if there is no sequence defined), then the group is marked as complete. +Any new messages for this group are sent to the discard channel (if defined). +Setting `expire-groups-upon-completion` to `true` (the default is `false`) removes the entire group, and any new messages (with the same correlation ID as the removed group) form a new group. +You can release partial sequences by using a `MessageGroupStoreReaper` together with `send-partial-result-on-expiry` being set to `true`. IMPORTANT: To facilitate discarding of late-arriving messages, the aggregator must maintain state about the group after it has been released. -This can eventually cause out of memory conditions. -To avoid such situations, you should consider configuring a `MessageGroupStoreReaper` to remove the group metadata; the expiry parameters should be set to expire groups after it is not expected that late messages will arrive. -For information about configuring a reaper, see <>. +This can eventually cause out-of-memory conditions. +To avoid such situations, you should consider configuring a `MessageGroupStoreReaper` to remove the group metadata. +The expiry parameters should be set to expire groups once a point has been reach after after which late messages are not expected to arrive. +For information about configuring a reaper, see "`<>`". -Spring Integration provides an out-of-the box implementation for `ReleaseStrategy`, the `SimpleSequenceSizeReleaseStrategy`. +Spring Integration provides an implementation for `ReleaseStrategy`: `SimpleSequenceSizeReleaseStrategy`. This implementation consults the `SEQUENCE_NUMBER` and `SEQUENCE_SIZE` headers of each arriving message to decide when a message group is complete and ready to be aggregated. -As shown above, it is also the default strategy. +As shown earlier, it is also the default strategy. -NOTE: Before _version 5.0_, the default release strategy was `SequenceSizeReleaseStrategy` which does not perform well with large groups. -With that strategy, duplicate sequence numbers are detected and rejected; this operation can be expensive. +NOTE: Before version 5.0, the default release strategy was `SequenceSizeReleaseStrategy`, which does not perform well with large groups. +With that strategy, duplicate sequence numbers are detected and rejected. +This operation can be expensive. If you are aggregating large groups, you don't need to release partial groups, and you don't need to detect/reject duplicate sequences, consider using the `SimpleSequenceSizeReleaseStrategy` instead - it is much more efficient for these use cases, and is the default since _version 5.0_ when partial group release is not specified. @@ -227,13 +209,14 @@ If you are aggregating large groups, you don't need to release partial groups, a The 4.3 release changed the default `Collection` for messages in a `SimpleMessageGroup` to `HashSet` (it was previously a `BlockingQueue`). This was expensive when removing individual messages from large groups (an O(n) linear scan was required). -Although the hash set is generally much faster for removing, it can be expensive for large messages because the hash has to be calculated (on both inserts and removes). +Although the hash set is generally much faster to remove, it can be expensive for large messages, because the hash has to be calculated on both inserts and removes. If you have messages that are expensive to hash, consider using some other collection type. -As discussed in <>, a `SimpleMessageGroupFactory` is provided so you can select the `Collection` that best suits your needs. +As discussed in "`<>`", a `SimpleMessageGroupFactory` is provided so that you can select the `Collection` that best suits your needs. You can also provide your own factory implementation to create some other `Collection>`. -Here is an example of how to configure an aggregator with the previous implementation and a `SimpleSequenceSizeReleaseStrategy`. +The following example shows how to configure an aggregator with the previous implementation and a `SimpleSequenceSizeReleaseStrategy`: +==== [source, xml] ---- ---- +==== ===== CorrelationStrategy The `CorrelationStrategy` interface is defined as follows: +==== [source,java] ---- public interface CorrelationStrategy { @@ -262,74 +247,76 @@ public interface CorrelationStrategy { } ---- +==== -The method returns an Object which represents the correlation key used for associating the message with a message group. -The key must satisfy the criteria used for a key in a Map with respect to the implementation of `equals()` and `hashCode()`. +The method returns an `Object` that represents the correlation key used for associating the message with a message group. +The key must satisfy the criteria used for a key in a `Map` with respect to the implementation of `equals()` and `hashCode()`. -In general, any POJO can implement the correlation logic, and the rules for mapping a message to a method's argument (or arguments) are the same as for a `ServiceActivator` (including support for @Header annotations). +In general, any POJO can implement the correlation logic, and the rules for mapping a message to a method's argument (or arguments) are the same as for a `ServiceActivator` (including support for `@Header` annotations). The method must return a value, and the value must not be `null`. -Spring Integration provides an out-of-the box implementation for `CorrelationStrategy`, the `HeaderAttributeCorrelationStrategy`. +Spring Integration provides an implementation for `CorrelationStrategy`: `HeaderAttributeCorrelationStrategy`. This implementation returns the value of one of the message headers (whose name is specified by a constructor argument) as the correlation key. -By default, the correlation strategy is a `HeaderAttributeCorrelationStrategy` returning the value of the `CORRELATION_ID` header attribute. -If you have a custom header name you would like to use for correlation, then simply configure that on an instance of `HeaderAttributeCorrelationStrategy` and provide that as a reference for the Aggregator's correlation-strategy. +By default, the correlation strategy is a `HeaderAttributeCorrelationStrategy` that returns the value of the `CORRELATION_ID` header attribute. +If you have a custom header name you would like to use for correlation, you can configure it on an instance of `HeaderAttributeCorrelationStrategy` and provide that as a reference for the aggregator's correlation strategy. -===== LockRegistry +===== `LockRegistry` -Changes to groups are thread safe; a `LockRegistry` is used to obtain a lock for the resolved correlation id. +Changes to groups are thread safe. +A `LockRegistry` is used to obtain a lock for the resolved correlation ID. A `DefaultLockRegistry` is used by default (in-memory). -For synchronizing updates across servers, where a shared `MessageGroupStore` is being used, a shared lock registry -must be configured. -See <> below for more information. +For synchronizing updates across servers, where a shared `MessageGroupStore` is being used, you must configure a shared lock registry. +See "`<>`" for more information. -[[aggregator-config]] -==== Configuring an Aggregator +[[aggregator-java-dsl]] +==== Configuring an Aggregator in Java DSL -See <> for configuring an Aggregator in Java DSL. +See "`<>`" for how to configure an aggregator in Java DSL. [[aggregator-xml]] ===== Configuring an Aggregator with XML -Spring Integration supports the configuration of an aggregator via XML through the `` element. -Below you can see an example of an aggregator. +Spring Integration supports the configuration of an aggregator with XML through the `` element. +The following example shows an example of an aggregator: +==== [source,xml] ---- - - auto-startup="true" <2> - input-channel="inputChannel" <3> - output-channel="outputChannel" <4> - discard-channel="throwAwayChannel" <5> - message-store="persistentMessageStore" <6> - order="1" <7> - send-partial-result-on-expiry="false" <8> - send-timeout="1000" <9> + + auto-startup="true" <2> + input-channel="inputChannel" <3> + output-channel="outputChannel" <4> + discard-channel="throwAwayChannel" <5> + message-store="persistentMessageStore" <6> + order="1" <7> + send-partial-result-on-expiry="false" <8> + send-timeout="1000" <9> - correlation-strategy="correlationStrategyBean" <10> - correlation-strategy-method="correlate" <11> - correlation-strategy-expression="headers['foo']" <12> + correlation-strategy="correlationStrategyBean" <10> + correlation-strategy-method="correlate" <11> + correlation-strategy-expression="headers['foo']" <12> - ref="aggregatorBean" <13> - method="aggregate" <14> + ref="aggregatorBean" <13> + method="aggregate" <14> - release-strategy="releaseStrategyBean" <15> - release-strategy-method="release" <16> - release-strategy-expression="size() == 5" <17> + release-strategy="releaseStrategyBean" <15> + release-strategy-method="release" <16> + release-strategy-expression="size() == 5" <17> - expire-groups-upon-completion="false" <18> - empty-group-min-timeout="60000" <19> + expire-groups-upon-completion="false" <18> + empty-group-min-timeout="60000" <19> - lock-registry="lockRegistry" <20> + lock-registry="lockRegistry" <20> - group-timeout="60000" <21> + group-timeout="60000" <21> group-timeout-expression="size() ge 2 ? 100 : -1" <22> - expire-groups-upon-timeout="true" <23> + expire-groups-upon-timeout="true" <23> - scheduler="taskScheduler" > <24> - <25> - <26> + scheduler="taskScheduler" > <24> + <25> + <26> @@ -347,143 +334,89 @@ Below you can see an example of an aggregator. ---- -<1> The id of the aggregator is _Optional_. - - - -<2> Lifecycle attribute signaling if aggregator should be started during Application Context startup. -_Optional (default is 'true')_. - - - -<3> The channel from which where aggregator will receive messages. -_Required_. - - - -<4> The channel to which the aggregator will send the aggregation results. -_Optional (because incoming messages can specify a reply channel themselves via 'replyChannel' Message Header)_. - - - -<5> The channel to which the aggregator will send the messages that timed out (if `send-partial-result-on-expiry` is _false_). -_Optional_. - - - +<1> The id of the aggregator is optional. +<2> Lifecycle attribute signaling whether the aggregator should be started during application context startup. +Optional (the default is 'true'). +<3> The channel from which where aggregator receives messages. +Required. +<4> The channel to which the aggregator sends the aggregation results. +Optional (because incoming messages can themselves specify a reply channel in the 'replyChannel' message header). +<5> The channel to which the aggregator sends the messages that timed out (if `send-partial-result-on-expiry` is `false`). +Optional. <6> A reference to a `MessageGroupStore` used to store groups of messages under their correlation key until they are complete. -_Optional_, by default a volatile in-memory store. - - - -<7> Order of this aggregator when more than one handle is subscribed to the same DirectChannel (use for load balancing purposes). -_Optional_. - - - -<8> Indicates that expired messages should be aggregated and sent to the 'output-channel' or 'replyChannel' once their containing `MessageGroup` is expired (see `MessageGroupStore.expireMessageGroups(long)`). -One way of expiring `MessageGroup` s is by configuring a `MessageGroupStoreReaper`. -However `MessageGroup` s can alternatively be expired by simply calling `MessageGroupStore.expireMessageGroups(timeout)`. -That could be accomplished via a Control Bus operation or by simply invoking that method if you have a reference to the `MessageGroupStore` instance. -Otherwise by itself this attribute has no behavior. -It only serves as an indicator of what to do (discard or send to the output/reply channel) with Messages that are still in the `MessageGroup` that is about to be expired. -_Optional_. -_Default - false_. -*NOTE:* This attribute is more properly `send-partial-result-on-timeout` because the group may not actually expire if +Optional. +By default, it is a volatile in-memory store. +// TODO How would one change it? +<7> The order of this aggregator when more than one handle is subscribed to the same `DirectChannel` (use for load-balancing purposes). +Optional. +<8> Indicates that expired messages should be aggregated and sent to the 'output-channel' or 'replyChannel' once their containing `MessageGroup` is expired (see https://docs.spring.io/spring-integration/api/org/springframework/integration/store/MessageGroupStore.html#expireMessageGroups-long[`MessageGroupStore.expireMessageGroups(long)`]). +One way of expiring a `MessageGroup` is by configuring a `MessageGroupStoreReaper`. +However you can alternatively expire `MessageGroup` by calling `MessageGroupStore.expireMessageGroups(timeout)`. +You can accomplish that through a Control Bus operation or, if you have a reference to the `MessageGroupStore` instance, by invoking `expireMessageGroups(timeout)`. +Otherwise, by itself, this attribute does nothing. +It serves only as an indicator of whether to discard or send to the output or reply channel any messages that are still in the `MessageGroup` that is about to be expired. +Optional (the default is `false`). +NOTE: This attribute might more properly be called `send-partial-result-on-timeout`, because the group may not actually expire if `expire-groups-upon-timeout` is set to `false`. - - - <9> The timeout interval to wait when sending a reply `Message` to the `output-channel` or `discard-channel`. -Defaults to `-1` - blocking indefinitely. -It is applied only if the output channel has some 'sending' limitations, e.g. -`QueueChannel` with a fixed 'capacity'. -In this case a `MessageDeliveryException` is thrown. -The `send-timeout` is ignored in case of `AbstractSubscribableChannel` implementations. -In case of `group-timeout(-expression)` the `MessageDeliveryException` from the scheduled expire task leads this task to be rescheduled. -_Optional_. - - - +Defaults to `-1`, which results in blocking indefinitely. +It is applied only if the output channel has some 'sending' limitations, such as a `QueueChannel` with a fixed 'capacity'. +In this case, a `MessageDeliveryException` is thrown. +For `AbstractSubscribableChannel` implementations, the `send-timeout` is ignored . +For `group-timeout(-expression)`, the `MessageDeliveryException` from the scheduled expire task leads this task to be rescheduled. +Optional. <10> A reference to a bean that implements the message correlation (grouping) algorithm. The bean can be an implementation of the `CorrelationStrategy` interface or a POJO. -In the latter case the correlation-strategy-method attribute must be defined as well. -_Optional (by default, the aggregator will use the `IntegrationMessageHeaderAccessor.CORRELATION_ID` header)_. - - - -<11> A method defined on the bean referenced by `correlation-strategy`, that implements the correlation decision algorithm. -_Optional, with restrictions (requires `correlation-strategy` to be present)._ - - - +In the latter case, the `correlation-strategy-method` attribute must be defined as well. +Optional (by default, the aggregator uses the `IntegrationMessageHeaderAccessor.CORRELATION_ID` header). +<11> A method defined on the bean referenced by `correlation-strategy`. +It implements the correlation decision algorithm. +Optional, with restrictions (`correlation-strategy` must be present). <12> A SpEL expression representing the correlation strategy. -Example: `"headers['foo']"`. +Example: `"headers['something']"`. Only one of `correlation-strategy` or `correlation-strategy-expression` is allowed. - - - <13> A reference to a bean defined in the application context. -The bean must implement the aggregation logic as described above. -_Optional (by default the list of aggregated Messages will become a payload of the output message)._ - - -<14> A method defined on the bean referenced by `ref`, that implements the message aggregation algorithm. -_Optional, depends on `ref` attribute being defined._ - - - +The bean must implement the aggregation logic, as described earlier. +Optional (by default, the list of aggregated messages becomes a payload of the output message). +<14> A method defined on the bean referenced by the `ref` attribute. +It implements the message aggregation algorithm. +Optional (it depends on `ref` attribute being defined). <15> A reference to a bean that implements the release strategy. The bean can be an implementation of the `ReleaseStrategy` interface or a POJO. -In the latter case the release-strategy-method attribute must be defined as well. -_Optional (by default, the aggregator will use the `IntegrationMessageHeaderAccessor.SEQUENCE_SIZE` header attribute)_. - - - -<16> A method defined on the bean referenced by `release-strategy`, that implements the completion decision algorithm. -_Optional, with restrictions (requires `release-strategy` to be present)._ - - - -<17> A SpEL expression representing the release strategy; the root object for the expression is a `MessageGroup`. +In the latter case, the `release-strategy-method` attribute must be defined as well. +Optional (by default, the aggregator uses the `IntegrationMessageHeaderAccessor.SEQUENCE_SIZE` header attribute). +<16> A method defined on the bean referenced by the `release-strategy` attribute. +It implements the completion decision algorithm. +Optional, with restrictions (`release-strategy` must be present). +<17> A SpEL expression representing the release strategy. +The root object for the expression is a `MessageGroup`. Example: `"size() == 5"`. Only one of `release-strategy` or `release-strategy-expression` is allowed. - - - -<18> When set to true (default false), completed groups are removed from the message store, allowing subsequent messages with the same correlation to form a new group. -The default behavior is to send messages with the same correlation as a completed group to the _discard-channel_. - - - -<19> Only applies if a `MessageGroupStoreReaper` is configured for the ``'s `MessageStore`. +<18> When set to `true` (the default is `false`), completed groups are removed from the message store, letting subsequent messages with the same correlation form a new group. +The default behavior is to send messages with the same correlation as a completed group to the `discard-channel`. +<19> Applies only if a `MessageGroupStoreReaper` is configured for the `MessageStore` of the ``. By default, when a `MessageGroupStoreReaper` is configured to expire partial groups, empty groups are also removed. -Empty groups exist after a group is released normally. -This is to enable the detection and discarding of late-arriving messages. +Empty groups exist after a group is normally released. +The empty groups enable the detection and discarding of late-arriving messages. If you wish to expire empty groups on a longer schedule than expiring partial groups, set this property. -Empty groups will then not be removed from the `MessageStore` until they have not been modified for at least this number of milliseconds. -Note that the actual time to expire an empty group will also be affected by the reaper's _timeout_ property and it could be as much as this value plus the timeout. - - - -<20> A reference to a `org.springframework.integration.util.LockRegistry` bean; used to obtain a `Lock` based on the `groupId` for concurrent operations on the `MessageGroup`. +Empty groups are then not removed from the `MessageStore` until they have not been modified for at least this number of milliseconds. +Note that the actual time to expire an empty group is also affected by the reaper's `timeout` property, and it could be as much as this value plus the timeout. +<20> A reference to a `org.springframework.integration.util.LockRegistry` bean. +It used to obtain a `Lock` based on the `groupId` for concurrent operations on the `MessageGroup`. By default, an internal `DefaultLockRegistry` is used. -Use of a distributed `LockRegistry`, such as the `ZookeeperLockRegistry`, ensures only one instance of the aggregator will operate on a group concurrently. -See <>, <>, <> for more information. - - - -<21> A timeout in milliseconds to force the `MessageGroup` complete, when the `ReleaseStrategy` doesn't _release_ the group when the current Message arrives. -This attribute provides a built-in _Time-base Release Strategy_ for the aggregator, when there is a need to emit a partial result (or discard the group), if a new Message does not arrive for the `MessageGroup` within the timeout. -When a new Message arrives at the aggregator, any existing `ScheduledFuture` for its `MessageGroup` is canceled. -If the `ReleaseStrategy` returns `false` (don't release) and the `groupTimeout > 0` a new task will be scheduled to expire the group. -Setting this attribute to zero (or negative value) is not advised because it will effectively disable the aggregator because every message group will be immediately completed. -It is possible, however to conditionally set it to zero (or negative value) using an expression; see `group-timeout-expression` for information. +Use of a distributed `LockRegistry`, such as the `ZookeeperLockRegistry`, ensures only one instance of the aggregator can operate on a group concurrently. +See "`<>`", "`<>`", and "`<>`" for more information. +<21> A timeout (in milliseconds) to force the `MessageGroup` complete when the `ReleaseStrategy` does not release the group when the current message arrives. +This attribute provides a built-in time-based release strategy for the aggregator when there is a need to emit a partial result (or discard the group) if a new message does not arrive for the `MessageGroup` within the timeout. +When a new message arrives at the aggregator, any existing `ScheduledFuture` for its `MessageGroup` is canceled. +If the `ReleaseStrategy` returns `false` (meaning do not release) and `groupTimeout > 0`, a new task is scheduled to expire the group. +We do not advise setting this attribute to zero (or a negative value). +Doing so effectively disables the aggregator, because every message group is immediately completed. +You can, however, conditionally set it to zero (or a negative value) by using an expression. +See `group-timeout-expression` for information. The action taken during the completion depends on the `ReleaseStrategy` and the `send-partial-group-on-expiry` attribute. -See <> for more information. -Mutually exclusive with 'group-timeout-expression' attribute. - - +See "`<>`" for more information. +It is mutually exclusive with 'group-timeout-expression' attribute. <22> The SpEL expression that evaluates to a `groupTimeout` with the `MessageGroup` as the `#root` evaluation context object. Used for scheduling the `MessageGroup` to be forced complete. If the expression evaluates to `null`, the completion is not scheduled. @@ -491,70 +424,67 @@ If it evaluates to zero, the group is completed immediately on the current threa In effect, this provides a dynamic `group-timeout` property. See `group-timeout` for more information. Mutually exclusive with 'group-timeout' attribute. - - <23> When a group is completed due to a timeout (or by a `MessageGroupStoreReaper`), the group is expired (completely removed) by default. -Late arriving messages will start a new group. -Set this to `false` to complete the group but have its metadata remain so that late arriving messages will be discarded. +Late arriving messages start a new group. +You can set this to `false` to complete the group but have its metadata remain so that late arriving messages are discarded. Empty groups can be expired later using a `MessageGroupStoreReaper` together with the `empty-group-min-timeout` attribute. -Default: 'true'. - - +It defaults to 'true'. <24> A `TaskScheduler` bean reference to schedule the `MessageGroup` to be forced complete if no new message arrives for the `MessageGroup` within the `groupTimeout`. -If not provided, the default scheduler `taskScheduler`, registered in the `ApplicationContext` (`ThreadPoolTaskScheduler`) will be used. +If not provided, the default scheduler (`taskScheduler`) registered in the `ApplicationContext` (`ThreadPoolTaskScheduler`) is used. This attribute does not apply if `group-timeout` or `group-timeout-expression` is not specified. - - -<25> Since _version 4.1_. -Allows a transaction to be started for the `forceComplete` operation. -It is initiated from a `group-timeout(-expression)` or by a `MessageGroupStoreReaper` and is not applied to the normal `add/release/discard` operations. +<25> Since version 4.1. +It lets a transaction be started for the `forceComplete` operation. +It is initiated from a `group-timeout(-expression)` or by a `MessageGroupStoreReaper` and is not applied to the normal `add`, `release`, and `discard` operations. Only this sub-element or `` is allowed. - - <26> Since _version 4.1_. -Allows the configuration of any `Advice` for the `forceComplete` operation. -It is initiated from a `group-timeout(-expression)` or by a `MessageGroupStoreReaper` and is not applied to the normal `add/release/discard` operations. +It allows the configuration of any `Advice` for the `forceComplete` operation. +It is initiated from a `group-timeout(-expression)` or by a `MessageGroupStoreReaper` and is not applied to the normal `add`, `release`, and `discard` operations. Only this sub-element or `` is allowed. -A transaction `Advice` can also be configured here using the Spring `tx` namespace. - - +A transaction `Advice` can also be configured here by using the Spring `tx` namespace. +==== [IMPORTANT] .Expiring Groups ===== There are two attributes related to expiring (completely removing) groups. -When a group is expired, there is no record of it and if a new message arrives with the same correlation, a new group is started. -When a group is completed (without expiry), the empty group remains and late arriving messages are discarded. -Empty groups can be removed later using a `MessageGroupStoreReaper` in combination with the `empty-group-min-timeout` attribute. +When a group is expired, there is no record of it, and, if a new message arrives with the same correlation, a new group is started. +When a group is completed (without expiry), the empty group remains and late-arriving messages are discarded. +Empty groups can be removed later by using a `MessageGroupStoreReaper` in combination with the `empty-group-min-timeout` attribute. -`expire-groups-upon-completion` relates to "normal" completion - when the `ReleaseStrategy` releases the group. +`expire-groups-upon-completion` relates to "`normal`" completion when the `ReleaseStrategy` releases the group. This defaults to `false`. -If a group is not completed normally, but is released or discarded because of a timeout, the group is normally expired. -Since _version 4.1_, you can now control this behavior using `expire-groups-upon-timeout`; this defaults to `true` for backwards compatibility. +If a group is not completed normally but is released or discarded because of a timeout, the group is normally expired. +Since version 4.1, you can control this behavior by using `expire-groups-upon-timeout`. +It defaults to `true` for backwards compatibility. -NOTE: When a group is timed out, the `ReleaseStrategy` is given one more opportunity to release the group; if it does so, and `expire-groups-upon-timeout` is false, then expiration is controlled by `expire-groups-upon-completion`. +NOTE: When a group is timed out, the `ReleaseStrategy` is given one more opportunity to release the group. +If it does so and `expire-groups-upon-timeout` is false, expiration is controlled by `expire-groups-upon-completion`. If the group is not released by the release strategy during timeout, then the expiration is controlled by the `expire-groups-upon-timeout`. -Timed-out groups are either discarded, or a partial release occurs (based on `send-partial-result-on-expiry`). +Timed-out groups are either discarded or a partial release occurs (based on `send-partial-result-on-expiry`). -Starting with _version 5.0_ empty groups are also scheduled for removal after `empty-group-min-timeout`. -If `expireGroupsUponCompletion == false` and `minimumTimeoutForEmptyGroups > 0`, the task to remove the group is scheduled, when normal or partial sequences release happens. +Since version 5.0, empty groups are also scheduled for removal after `empty-group-min-timeout`. +If `expireGroupsUponCompletion == false` and `minimumTimeoutForEmptyGroups > 0`, the task to remove the group is scheduled when normal or partial sequences release happens. ===== -Using a `ref` attribute is generally recommended if a custom aggregator handler implementation may be referenced in other `` definitions. -However if a custom aggregator implementation is only being used by a single definition of the ``, you can use an inner bean definition (starting with version 1.0.3) to configure the aggregation POJO within the `` element: +We generally recommend using a `ref` attribute if a custom aggregator handler implementation may be referenced in other `` definitions. +However, if a custom aggregator implementation is only being used by a single definition of the ``, you can use an inner bean definition (starting with version 1.0.3) to configure the aggregation POJO within the `` element, as the following example shows: + +==== [source,xml] ---- ---- +==== NOTE: Using both a `ref` attribute and an inner bean definition in the same `` configuration is not allowed, as it creates an ambiguous condition. -In such cases, an Exception will be thrown. +In such cases, an Exception is thrown. -An example implementation of the aggregator bean looks as follows: +The following example shows an implementation of the aggregator bean: +==== [source,java] ---- public class PojoAggregator { @@ -568,9 +498,11 @@ public class PojoAggregator { } } ---- +==== -An implementation of the completion strategy bean for the example above may be as follows: +An implementation of the completion strategy bean for the preceding example might be as follows: +==== [source,java] ---- public class PojoReleaseStrategy { @@ -584,11 +516,13 @@ public class PojoReleaseStrategy { } } ---- +==== -NOTE: Wherever it makes sense, the release strategy method and the aggregator method can be combined in a single bean. +NOTE: Wherever it makes sense to do so, the release strategy method and the aggregator method can be combined into a single bean. -An implementation of the correlation strategy bean for the example above may be as follows: +An implementation of the correlation strategy bean for the example above might be as follows: +==== [source,java] ---- public class PojoCorrelationStrategy { @@ -598,20 +532,24 @@ public class PojoCorrelationStrategy { } } ---- +==== -For example, this aggregator would group numbers by some criterion (in our case the remainder after dividing by 10) and will hold the group until the sum of the numbers provided by the payloads exceeds a certain value. +The aggregator in the preceding example would group numbers by some criterion (in this case, the remainder after dividing by ten) and hold the group until the sum of the numbers provided by the payloads exceeds a certain value. -NOTE: Wherever it makes sense, the release strategy method, correlation strategy method and the aggregator method can be combined in a single bean (all of them or any two). +NOTE: Wherever it makes sense to do so, the release strategy method, the correlation strategy method, and the aggregator method can be combined in a single bean. +(Actually, all of them or any two of them can be combined.) [[aggregator-spel]] ====== Aggregators and Spring Expression Language (SpEL) -Since Spring Integration 2.0, the various strategies (correlation, release, and aggregation) may be handled with http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html[SpEL] which is recommended if the logic behind such _release strategy_ is relatively simple. -Let's say you have a legacy component that was designed to receive an array of objects. -We know that the default release strategy will assemble all aggregated messages in the List. -So now we have two problems. -First we need to extract individual messages from the list, and then we need to extract the payload of each message and assemble the array of objects (see code below). +Since Spring Integration 2.0, you can handle the various strategies (correlation, release, and aggregation) with http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html[SpEL], which we recommend if the logic behind such a release strategy is relatively simple. +Suppose you have a legacy component that was designed to receive an array of objects. +We know that the default release strategy assembles all aggregated messages in the `List`. +Now we have two problems. +First, we need to extract individual messages from the list. Second, we need to extract the payload of each message and assemble the array of objects. +The following example solves both problems: +==== [source,java] ---- public String[] processRelease(List> messages){ @@ -622,50 +560,59 @@ public String[] processRelease(List> messages){ return stringList.toArray(new String[]{}); } ---- +==== -However, with SpEL such a requirement could actually be handled relatively easily with a one-line expression, thus sparing you from writing a custom class and configuring it as a bean. +However, with SpEL, such a requirement could actually be handled relatively easily with a one-line expression, thus sparing you from writing a custom class and configuring it as a bean. +The following example shows how to do so: +==== [source,xml] ---- ---- +==== -In the above configuration we are using a http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-collection-projection[Collection Projection] expression to assemble a new collection from the payloads of all messages in the list and then transforming it to an Array, thus achieving the same result as the java code above. +In the preceding configuration, we use a http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-collection-projection[collection projection] expression to assemble a new collection from the payloads of all the messages in the list and then transform it to an array, thus achieving the same result as the earlier Java code. -The same expression-based approach can be applied when dealing with custom _Release_ and _Correlation_ strategies. +You can apply the same expression-based approach when dealing with custom release and correlation strategies. -Instead of defining a bean for a custom `CorrelationStrategy` via the `correlation-strategy` attribute, you can implement your simple correlation logic via a SpEL expression and configure it via the `correlation-strategy-expression` attribute. +Instead of defining a bean for a custom `CorrelationStrategy` in the `correlation-strategy` attribute, you can implement your simple correlation logic as a SpEL expression and configure it in the `correlation-strategy-expression` attribute, as the following example shows: -For example: +==== [source,xml] ---- correlation-strategy-expression="payload.person.id" ---- +==== -In the above example it is assumed that the payload has an attribute `person` with an `id` which is going to be used to correlate messages. +In the preceding example, we assume that the payload has a `person` attribute with an `id`, which is going to be used to correlate messages. -Likewise, for the `ReleaseStrategy` you can implement your release logic as a SpEL expression and configure it via the `release-strategy-expression` attribute. +Likewise, for the `ReleaseStrategy`, you can implement your release logic as a SpEL expression and configure it in the `release-strategy-expression` attribute. The root object for evaluation context is the `MessageGroup` itself. -The List of messages can be referenced using the `message` property of the group within the expression. +The `List` of messages can be referenced by using the `message` property of the group within the expression. -NOTE: In releases prior to _version 5.0_, the root object was the collection of `Message`. +NOTE: In releases prior to version 5.0, the root object was the collection of `Message`, as the previous example shows: -For example: +==== [source,xml] ---- release-strategy-expression="!messages.?[payload==5].empty" ---- +==== -In this example the root object of the SpEL Evaluation Context is the `MessageGroup` itself, and you are simply stating that as soon as there are a message with payload as `5` in this group, it should be released. +In the preceding example, the root object of the SpEL evaluation context is the `MessageGroup` itself, and you are stating that, as soon as there is a message with payload of `5` in this group, the group should be released. [[agg-and-group-to]] ====== Aggregator and Group Timeout -Starting with _version 4.0_, two new mutually exclusive attributes have been introduced: `group-timeout` and `group-timeout-expression` (see the description above). -There are some cases where it is needed to emit the aggregator result (or discard the group) after a timeout if the `ReleaseStrategy` doesn't _release_ when the current Message arrives. -For this purpose the `groupTimeout` option allows scheduling the `MessageGroup` to be forced complete: +Starting with version 4.0, two new mutually exclusive attributes have been introduced: `group-timeout` and `group-timeout-expression` (see the earlier description). +// TODO This needs a link, but I don't see a target for it. +In some cases, you may need to emit the aggregator result (or discard the group) after a timeout if the `ReleaseStrategy` does not release when the current message arrives. +For this purpose, the `groupTimeout` option lets scheduling the `MessageGroup` be forced to complete, as the following example shows: + +==== [source,xml] ---- ---- +==== -With this example, the normal _release_ will be possible if the aggregator receives the last message in sequence as defined by the `release-strategy-expression`. -If that specific message does not arrive, the `groupTimeout` will force the group complete after 10 seconds as long as the group contains at least 2 Messages. +With this example, the normal release is possible if the aggregator receives the last message in sequence as defined by the `release-strategy-expression`. +If that specific message does not arrive, the `groupTimeout` forces the group to complete after ten seconds, as long as the group contains at least two Messages. -The results of forcing the group complete depends on the `ReleaseStrategy` and the `send-partial-result-on-expiry`. -First, the release strategy is again consulted to see if a _normal_ release is to be made - while the group won't have changed, the `ReleaseStrategy` can decide to release the group at this time. -If the release strategy still does not release the group, it will be expired. -If `send-partial-result-on-expiry` is `true`, existing messages in the (partial) `MessageGroup` will be released as a normal aggregator reply Message to the `output-channel`, otherwise it will be discarded. +The results of forcing the group to complete depends on the `ReleaseStrategy` and the `send-partial-result-on-expiry`. +First, the release strategy is again consulted to see if a normal release is to be made. +While the group has not changed, the `ReleaseStrategy` can decide to release the group at this time. +If the release strategy still does not release the group, it is expired. +If `send-partial-result-on-expiry` is `true`, existing messages in the (partial) `MessageGroup` are released as a normal aggregator reply message to the `output-channel`. +Otherwise, it is discarded. -There is a difference between `groupTimeout` behavior and `MessageGroupStoreReaper` (see <>). +There is a difference between `groupTimeout` behavior and `MessageGroupStoreReaper` (see "`<>`"). The reaper initiates forced completion for all `MessageGroup` s in the `MessageGroupStore` periodically. -The `groupTimeout` does it for each `MessageGroup` individually, if a new Message doesn't arrive during the `groupTimeout`. -Also, the reaper can be used to remove empty groups (empty groups are retained in order to discard late messages, if `expire-groups-upon-completion` is false). +The `groupTimeout` does it for each `MessageGroup` individually if a new message does not arrive during the `groupTimeout`. +Also, the reaper can be used to remove empty groups (empty groups are retained in order to discard late messages if `expire-groups-upon-completion` is false). [[aggregator-annotations]] ===== Configuring an Aggregator with Annotations -An aggregator configured using annotations would look like this. +The following example shows an aggregator configured with annotations: +=== [source,java] ---- public class Waiter { @@ -714,29 +665,20 @@ public class Waiter { } ---- -<1> An annotation indicating that this method shall be used as an aggregator. -Must be specified if this class will be used as an aggregator. +<1> An annotation indicating that this method should be used as an aggregator. +It must be specified if this class is used as an aggregator. +<2> An annotation indicating that this method is used as the release strategy of an aggregator. +If not present on any method, the aggregator uses the `SimpleSequenceSizeReleaseStrategy`. +<3> An annotation indicating that this method should be used as the correlation strategy of an aggregator. +If no correlation strategy is indicated, the aggregator uses the `HeaderAttributeCorrelationStrategy` based on `CORRELATION_ID`. +==== - - -<2> An annotation indicating that this method shall be used as the release strategy of an aggregator. -If not present on any method, the aggregator will use the `SimpleSequenceSizeReleaseStrategy`. - - - -<3> An annotation indicating that this method shall be used as the correlation strategy of an aggregator. -If no correlation strategy is indicated, the aggregator will use the `HeaderAttributeCorrelationStrategy` based on `CORRELATION_ID`. - - -All of the configuration options provided by the xml element are also available for the `@Aggregator` annotation. +All of the configuration options provided by the XML element are also available for the `@Aggregator` annotation. The aggregator can be either referenced explicitly from XML or, if the `@MessageEndpoint` is defined on the class, detected automatically through classpath scanning. -Annotation configuration (`@Aggregator` and others) for the Aggregator component covers only simple use cases, -where most default options are sufficient. -If you need more control over those options using Annotation configuration, consider using -a `@Bean` definition for the `AggregatingMessageHandler` and mark its -`@Bean` method with `@ServiceActivator`: +Annotation configuration (`@Aggregator` and others) for the Aggregator component covers only simple use cases, where most default options are sufficient. +If you need more control over those options when using annotation configuration, consider using a `@Bean` definition for the `AggregatingMessageHandler` and mark its `@Bean` method with `@ServiceActivator`, as the following example shows: [source,java] ---- @@ -753,19 +695,19 @@ public MessageHandler aggregator(MessageGroupStore jdbcMessageGroupStore) { } ---- -See <> and <> for more information. +See "`<>`" and "`<>`" for more information. -NOTE: Starting with the _version 4.2_ the `AggregatorFactoryBean` is available, to simplify Java configuration -for the `AggregatingMessageHandler`. +NOTE: Starting with version 4.2, the `AggregatorFactoryBean` is available to simplify Java configuration for the `AggregatingMessageHandler`. [[reaper]] -==== Managing State in an Aggregator: MessageGroupStore +==== Managing State in an Aggregator: `MessageGroupStore` Aggregator (and some other patterns in Spring Integration) is a stateful pattern that requires decisions to be made based on a group of messages that have arrived over a period of time, all with the same correlation key. -The design of the interfaces in the stateful patterns (e.g. -`ReleaseStrategy`) is driven by the principle that the components (whether defined by the framework or a user) should be able to remain stateless. +The design of the interfaces in the stateful patterns (such as `ReleaseStrategy`) is driven by the principle that the components (whether defined by the framework or by a user) should be able to remain stateless. All state is carried by the `MessageGroup` and its management is delegated to the `MessageGroupStore`. +The `MessageGroupStore` interface is defined as follows: +==== [source,java] ---- public interface MessageGroupStore { @@ -793,13 +735,15 @@ public interface MessageGroupStore { int expireMessageGroups(long timeout); } ---- +==== -For more information please refer to the http://docs.spring.io/spring-integration/api/org/springframework/integration/store/MessageGroupStore.html[JavaDoc]. +For more information, see the http://docs.spring.io/spring-integration/api/org/springframework/integration/store/MessageGroupStore.html[Javadoc]. The `MessageGroupStore` accumulates state information in `MessageGroups` while waiting for a release strategy to be triggered, and that event might not ever happen. -So to prevent stale messages from lingering, and for volatile stores to provide a hook for cleaning up when the application shuts down, the `MessageGroupStore` allows the user to register callbacks to apply to its `MessageGroups` when they expire. -The interface is very straightforward: +So, to prevent stale messages from lingering, and for volatile stores to provide a hook for cleaning up when the application shuts down, the `MessageGroupStore` lets you register callbacks to apply to its `MessageGroups` when they expire. +The interface is very straightforward, as the following listing shows: +==== [source,java] ---- public interface MessageGroupCallback { @@ -808,18 +752,20 @@ public interface MessageGroupCallback { } ---- +==== -The callback has direct access to the store and the message group so it can manage the persistent state (e.g. -by removing the group from the store entirely). +The callback has direct access to the store and the message group so that it can manage the persistent state (for example, by entirely removing the group from the store). -The `MessageGroupStore` maintains a list of these callbacks which it applies, on demand, to all messages whose timestamp is earlier than a time supplied as a parameter (see the `registerMessageGroupExpiryCallback(..)` and `expireMessageGroups(..)` methods above). +The `MessageGroupStore` maintains a list of these callbacks, which it applies, on demand, to all messages whose timestamps are earlier than a time supplied as a parameter (see the `registerMessageGroupExpiryCallback(..)` and `expireMessageGroups(..)` methods, described earlier). +For more detail, see "`<>`". -The `expireMessageGroups` method can be called with a timeout value. -Any message older than the current time minus this value will be expired, and have the callbacks applied. -Thus it is the user of the store that defines what is meant by message group "expiry". +You can call the `expireMessageGroups` method with a timeout value. +Any message older than the current time minus this value is expired and has the callbacks applied. +Thus, it is the user of the store that defines what is meant by message group "`expiry`". -As a convenience for users, Spring Integration provides a wrapper for the message expiry in the form of a `MessageGroupStoreReaper`: +As a convenience for users, Spring Integration provides a wrapper for the message expiry in the form of a `MessageGroupStoreReaper`, as the following example shows: +==== [source,xml] ---- @@ -831,25 +777,29 @@ As a convenience for users, Spring Integration provides a wrapper for the messag ---- +==== -The reaper is a `Runnable`, and all that is happening in the example above is that the message group store's expire method is being called once every 10 seconds. +The reaper is a `Runnable`. +In the preceding example, the message group store's expire method is called every ten seconds. The timeout itself is 30 seconds. -NOTE: It is important to understand that the 'timeout' property of the `MessageGroupStoreReaper` is an approximate value and is impacted by the the rate of the task scheduler since this property will only be checked on the next scheduled execution of the `MessageGroupStoreReaper` task. -For example if the timeout is set for 10 min, but the `MessageGroupStoreReaper` task is scheduled to run every 60 min and the last execution of the `MessageGroupStoreReaper` task happened 1 min before the timeout, the `MessageGroup` will not expire for the next 59 min. -So it is recommended to set the rate at least equal to the value of the timeout or shorter. +NOTE: It is important to understand that the 'timeout' property of `MessageGroupStoreReaper` is an approximate value and is impacted by the the rate of the task scheduler, since this property is only checked on the next scheduled execution of the `MessageGroupStoreReaper` task. +For example, if the timeout is set for ten minutes but the `MessageGroupStoreReaper` task is scheduled to run every hour and the last execution of the `MessageGroupStoreReaper` task happened one minute before the timeout, the `MessageGroup` does not expire for the next 59 minutes. +Consequently, we recommend setting the rate to be at least equal to the value of the timeout or shorter. -In addition to the reaper, the expiry callbacks are invoked when the application shuts down via a lifecycle callback in the `AbstractCorrelatingMessageHandler`. +In addition to the reaper, the expiry callbacks are invoked when the application shuts down through a lifecycle callback in the `AbstractCorrelatingMessageHandler`. The `AbstractCorrelatingMessageHandler` registers its own expiry callback, and this is the link with the boolean flag `send-partial-result-on-expiry` in the XML configuration of the aggregator. -If the flag is set to true, then when the expiry callback is invoked, any unmarked messages in groups that are not yet released can be sent on to the output channel. +If the flag is set to `true`, then, when the expiry callback is invoked, any unmarked messages in groups that are not yet released can be sent on to the output channel. [IMPORTANT] ===== -When a shared `MessageStore` is used for different correlation endpoints, it is necessary to configure a proper `CorrelationStrategy` to ensure uniqueness for group ids. -Otherwise unexpected behavior may happen when one correlation endpoint may release or expire messages from others - messages with the same correlation key are stored in the same message group. +When a shared `MessageStore` is used for different correlation endpoints, you must configure a proper `CorrelationStrategy` to ensure uniqueness for group IDs. +Otherwise, unexpected behavior may happen when one correlation endpoint releases or expire messages from others. +Messages with the same correlation key are stored in the same message group. -Some `MessageStore` implementations allow using the same physical resources, by partitioning the data; for example, the `JdbcMessageStore` has a `region` property; the `MongoDbMessageStore` has a `collectionName` property. +Some `MessageStore` implementations allow using the same physical resources, by partitioning the data. +For example, the `JdbcMessageStore` has a `region` property, and the `MongoDbMessageStore` has a `collectionName` property. -For more information about `MessageStore` interface and its implementations, please read <>. +For more information about the `MessageStore` interface and its implementations, see "`<>`". ===== diff --git a/src/reference/asciidoc/amqp.adoc b/src/reference/asciidoc/amqp.adoc index fccdf74c00..6b04a10394 100644 --- a/src/reference/asciidoc/amqp.adoc +++ b/src/reference/asciidoc/amqp.adoc @@ -1,10 +1,7 @@ [[amqp]] == AMQP Support -[[amqp-introduction]] -=== Introduction - -Spring Integration provides Channel Adapters for receiving and sending messages using the Advanced Message Queuing Protocol (AMQP). +Spring Integration provides channel adapters for receiving and sending messages by using the Advanced Message Queuing Protocol (AMQP). The following adapters are available: * <> @@ -13,219 +10,175 @@ The following adapters are available: * <> * <> -Spring Integration also provides a point-to-point Message Channel as well as a publish/subscribe Message Channel backed by AMQP Exchanges and Queues. +Spring Integration also provides a point-to-point message channel and a publish-subscribe message channel backed by AMQP Exchanges and Queues. -In order to provide AMQP support, Spring Integration relies on (http://projects.spring.io/spring-amqp[Spring AMQP]) -which "applies core Spring concepts to the development of AMQP-based messaging solutions". +To provide AMQP support, Spring Integration relies on (http://projects.spring.io/spring-amqp[Spring AMQP]), which applies core Spring concepts to the development of AMQP-based messaging solutions. Spring AMQP provides similar semantics to (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jms.html[Spring JMS]). -Whereas the provided AMQP Channel Adapters are intended for unidirectional Messaging (send or receive) only, Spring Integration also provides inbound and outbound AMQP Gateways for request/reply operations. +Whereas the provided AMQP Channel Adapters are intended for unidirectional messaging (send or receive) only, Spring Integration also provides inbound and outbound AMQP gateways for request-reply operations. + +TIP: +You should familiarize yourself with the +http://docs.spring.io/spring-amqp/reference/html/[reference documentation of the Spring AMQP project]. +It provides much more in-depth information about Spring's integration with AMQP in general and RabbitMQ in particular. -[TIP] -===== -Please familiarize yourself with the -http://docs.spring.io/spring-amqp/reference/html/[reference documentation of the Spring AMQP project as well]. -It provides much more in-depth information regarding Spring's integration with AMQP in general and RabbitMQ in particular. -===== [[amqp-inbound-channel-adapter]] === Inbound Channel Adapter -A configuration sample for an AMQP Inbound Channel Adapter is shown below. +The following listing shows the possible configuration options for an AMQP Inbound Channel Adapter: +==== [source, xml] ---- - channel="inboundChannel" <2> - queue-names="si.test.queue" <3> - acknowledge-mode="AUTO" <4> - advice-chain="" <5> - channel-transacted="" <6> - concurrent-consumers="" <7> - connection-factory="" <8> - error-channel="" <9> - expose-listener-channel="" <10> - header-mapper="" <11> - mapped-request-headers="" <12> - listener-container="" <13> - message-converter="" <14> + id="inboundAmqp" <1> + channel="inboundChannel" <2> + queue-names="si.test.queue" <3> + acknowledge-mode="AUTO" <4> + advice-chain="" <5> + channel-transacted="" <6> + concurrent-consumers="" <7> + connection-factory="" <8> + error-channel="" <9> + expose-listener-channel="" <10> + header-mapper="" <11> + mapped-request-headers="" <12> + listener-container="" <13> + message-converter="" <14> message-properties-converter="" <15> - phase="" <16> - prefetch-count="" <17> - receive-timeout="" <18> - recovery-interval="" <19> - missing-queues-fatal="" <20> - shutdown-timeout="" <21> - task-executor="" <22> - transaction-attribute="" <23> - transaction-manager="" <24> - tx-size="" <25> - consumers-per-queue /> <26> + phase="" <16> + prefetch-count="" <17> + receive-timeout="" <18> + recovery-interval="" <19> + missing-queues-fatal="" <20> + shutdown-timeout="" <21> + task-executor="" <22> + transaction-attribute="" <23> + transaction-manager="" <24> + tx-size="" <25> + consumers-per-queue /> <26> ---- -<1> Unique ID for this adapter. -_Optional_. - - -<2> Message Channel to which converted Messages should be sent. -_Required_. - - -<3> Names of the AMQP Queues from which Messages should be consumed (comma-separated list)._Required_. - - -<4> Acknowledge Mode for the `MessageListenerContainer`. -When set to MANUAL, the delivery tag and channel are provided in message headers `amqp_deliveryTag` and `amqp_channel` respectively; the user application is responsible for acknowledgement. -NONE means no acknowledgements (autoAck); AUTO means the adapter's container will acknowledge when the downstream flow completes._Optional (Defaults to AUTO)_ see <>. - - -<5> Extra AOP Advice(s) to handle cross cutting behavior associated with this Inbound Channel Adapter. -_Optional_. - - -<6> Flag to indicate that channels created by this component will be transactional. -If true, tells the framework to use a transactional channel and to end all operations (send or receive) with a commit or rollback depending on the outcome, with an exception signalling a rollback. -_Optional (Defaults to false)_. - - +<1> The unique ID for this adapter. +Optional. +<2> Message channel to which converted messages should be sent. +Required. +<3> Names of the AMQP queues (comma-separated list) from which messages should be consumed. +Required. +<4> Acknowledge mode for the `MessageListenerContainer`. +When set to `MANUAL`, the delivery tag and channel are provided in message headers `amqp_deliveryTag` and `amqp_channel`, respectively. +The user application is responsible for acknowledgement. +`NONE` means no acknowledgements (`autoAck`). +`AUTO` means the adapter's container acknowledges when the downstream flow completes. +Optional (defaults to AUTO). +See "`<>`". +<5> Extra AOP Advices to handle cross-cutting behavior associated with this inbound channel adapter. +Optional. +<6> Flag to indicate that channels created by this component are transactional. +If true, it tells the framework to use a transactional channel and to end all operations (send or receive) with a commit or rollback, depending on the outcome, with an exception that signals a rollback. +Optional (Defaults to false). <7> Specify the number of concurrent consumers to create. -Default is 1. -Raising the number of concurrent consumers is recommended in order to scale the consumption of messages coming in from a queue. +The default is `1`. +We recommend raising the number of concurrent consumers to scale the consumption of messages coming in from a queue. However, note that any ordering guarantees are lost once multiple consumers are registered. -In general, use 1 consumer for low-volume queues. +In general, use one consumer for low-volume queues. Not allowed when 'consumers-per-queue' is set. -_Optional_. - - -<8> Bean reference to the RabbitMQ ConnectionFactory. -_Optional (Defaults to 'connectionFactory')_. - - -<9> Message Channel to which error Messages should be sent. -_Optional_. - - -<10> Shall the listener channel (com.rabbitmq.client.Channel) be exposed to a registered `ChannelAwareMessageListener`. -_Optional (Defaults to true)_. - - +Optional. +<8> Bean reference to the RabbitMQ `ConnectionFactory`. +Optional (defaults to 'connectionFactory'). +<9> Message channel to which error messages should be sent. +Optional. +<10> Whether the listener channel (com.rabbitmq.client.Channel) is exposed to a registered `ChannelAwareMessageListener`. +Optional (defaults to true). <11> A reference to an `AmqpHeaderMapper` to use when receiving AMQP Messages. -_Optional_. -By default only standard AMQP properties (e.g. -`contentType`) will be copied to Spring Integration `MessageHeaders`. -Any user-defined headers within the AMQP `MessageProperties` will NOT be copied to the Message by the default `DefaultAmqpHeaderMapper`. +Optional. +By default, only standard AMQP properties (such as `contentType`) are copied to Spring Integration `MessageHeaders`. +Any user-defined headers within the AMQP `MessageProperties` are NOT copied to the message by the default `DefaultAmqpHeaderMapper`. Not allowed if 'request-header-names' is provided. - - -<12> Comma-separated list of names of AMQP Headers to be mapped from the AMQP request into the MessageHeaders. +<12> Comma-separated list of the names of AMQP Headers to be mapped from the AMQP request into the `MessageHeaders`. This can only be provided if the 'header-mapper' reference is not provided. -The values in this list can also be simple patterns to be matched against the header names (e.g. -"\*" or "foo*, bar" or "*foo"). - - +The values in this list can also be simple patterns to be matched against the header names (such as "\*" or "thing1*, thing2" or "*something"). <13> Reference to the `AbstractMessageListenerContainer` to use for receiving AMQP Messages. -If this attribute is provided, then no other attribute related to the listener container configuration should be provided. -In other words, by setting this reference, you must take full responsibility of the listener container configuration. -The only exception is the MessageListener itself. -Since that is actually the core responsibility of this Channel Adapter implementation, the referenced listener container must NOT already have its own MessageListener configured. -_Optional_. - - -<14> The MessageConverter to use when receiving AMQP Messages. -_Optional_. - - -<15> The MessagePropertiesConverter to use when receiving AMQP Messages. -_Optional_. - - -<16> Specify the phase in which the underlying `AbstractMessageListenerContainer` should be started and stopped. +If this attribute is provided, no other attribute related to the listener container configuration should be provided. +In other words, by setting this reference, you must take full responsibility for the listener container configuration. +The only exception is the `MessageListener` itself. +Since that is actually the core responsibility of this channel adapter implementation, the referenced listener container must not already have its own `MessageListener`. +Optional. +<14> The `MessageConverter` to use when receiving AMQP messages. +Optional. +<15> The `MessagePropertiesConverter` to use when receiving AMQP messages. +Optional. +<16> Specifies the phase in which the underlying `AbstractMessageListenerContainer` should be started and stopped. The startup order proceeds from lowest to highest, and the shutdown order is the reverse of that. -By default this value is Integer.MAX_VALUE meaning that this container starts as late as possible and stops as soon as possible. -_Optional_. - - +By default, this value is `Integer.MAX_VALUE`, meaning that this container starts as late as possible and stops as soon as possible. +Optional. <17> Tells the AMQP broker how many messages to send to each consumer in a single request. -Often this can be set quite high to improve throughput. -It should be greater than or equal to the transaction size (see attribute "tx-size"). -_Optional (Defaults to 1)_. - - +Often, you can set this value high to improve throughput. +It should be greater than or equal to the transaction size (see the `tx-size` attribute, later in this list). +Optional (defaults to `1`). <18> Receive timeout in milliseconds. -_Optional (Defaults to 1000)_. - - -<19> Specifies the interval between recovery attempts of the underlying `AbstractMessageListenerContainer` (in milliseconds) -._Optional (Defaults to 5000)_. - - -<20> If 'true', and none of the queues are available on the broker, the container will throw a fatal exception during startup and will stop if the queues are deleted when the container is running (after making 3 attempts to passively declare the queues). -If false, the container will not throw an exception and go into recovery mode, attempting to restart according to the `recovery-interval`. -_Optional (Defaults to `true`)_. - - -<21> The time to wait for workers in milliseconds after the underlying `AbstractMessageListenerContainer` is stopped, and before the AMQP connection is forced closed. -If any workers are active when the shutdown signal comes they will be allowed to finish processing as long as they can finish within this timeout. -Otherwise the connection is closed and messages remain unacked (if the channel is transactional). -_Optional (Defaults to 5000)_. - - -<22> By default, the underlying `AbstractMessageListenerContainer` uses a SimpleAsyncTaskExecutor implementation, that fires up a new Thread for each task, executing it asynchronously. +Optional (defaults to `1000`). +<19> Specifies the interval between recovery attempts of the underlying `AbstractMessageListenerContainer` (in milliseconds). +Optional (defaults to `5000`). +<20> If 'true' and none of the queues are available on the broker, the container throws a fatal exception during startup and stops if the queues are deleted when the container is running (after making three attempts to passively declare the queues). +If `false`, the container does not throw an exception and goes into recovery mode, attempting to restart according to the `recovery-interval`. +Optional (defaults to `true`). +<21> The time to wait for workers (in milliseconds) after the underlying `AbstractMessageListenerContainer` is stopped and before the AMQP connection is forced closed. +If any workers are active when the shutdown signal comes, they are allowed to finish processing as long as they can finish within this timeout. +Otherwise, the connection is closed and messages remain unacknowledged (if the channel is transactional). +Optional (defaults to `5000`). +<22> By default, the underlying `AbstractMessageListenerContainer` uses a `SimpleAsyncTaskExecutor` implementation, that fires up a new thread for each task, running it asynchronously. By default, the number of concurrent threads is unlimited. -*NOTE:* This implementation does not reuse threads. -Consider a thread-pooling TaskExecutor implementation as an alternative. -_Optional (Defaults to SimpleAsyncTaskExecutor)_. - - -<23> By default the underlying `AbstractMessageListenerContainer` creates a new instance of the DefaultTransactionAttribute (takes the EJB approach to rolling back on runtime, but not checked exceptions. -_Optional (Defaults to DefaultTransactionAttribute)_. - - -<24> Sets a Bean reference to an external `PlatformTransactionManager` on the underlying AbstractMessageListenerContainer. -The transaction manager works in conjunction with the "channel-transacted" attribute. -If there is already a transaction in progress when the framework is sending or receiving a message, and the channelTransacted flag is true, then the commit or rollback of the messaging transaction will be deferred until the end of the current transaction. -If the channelTransacted flag is false, then no transaction semantics apply to the messaging operation (it is auto-acked). -For further information see +Note that this implementation does not reuse threads. +Consider using a thread-pooling `TaskExecutor` implementation as an alternative. +Optional (defaults to `SimpleAsyncTaskExecutor`). +<23> By default, the underlying `AbstractMessageListenerContainer` creates a new instance of the `DefaultTransactionAttribute` (it takes the EJB approach to rolling back on runtime but not checked exceptions). +Optional (defaults to `DefaultTransactionAttribute`). +<24> Sets a bean reference to an external `PlatformTransactionManager` on the underlying `AbstractMessageListenerContainer`. +The transaction manager works in conjunction with the `channel-transacted` attribute. +If there is already a transaction in progress when the framework is sending or receiving a message and the `channelTransacted` flag is `true`, the commit or rollback of the messaging transaction is deferred until the end of the current transaction. +If the `channelTransacted` flag is `false`, no transaction semantics apply to the messaging operation (it is auto-acked). +For further information, see http://docs.spring.io/spring-amqp/reference/html/%5Freference.html#%5Ftransactions[Transactions with Spring AMQP]. -_Optional_. - - +Optional. <25> Tells the `SimpleMessageListenerContainer` how many messages to process in a single transaction (if the channel is transactional). -For best results it should be less than or equal to the set "prefetch-count". +For best results, it should be less than or equal to the value set in `prefetch-count`. Not allowed when 'consumers-per-queue' is set. -_Optional (Defaults to 1)_. - +Optional (defaults to `1`). <26> Indicates that the underlying listener container should be a `DirectMessageListenerContainer` instead of the default `SimpleMessageListenerContainer`. -Refer to the Spring AMQP Reference Manual for more information. - +See the https://docs.spring.io/spring-amqp/reference/html/[Spring AMQP Reference Manual] for more information. +==== [NOTE] .container -===== -Note that when configuring an external container, you cannot use the *Spring AMQP* namespace to define the container. +==== +Note that when configuring an external container, you cannot use the Spring AMQP namespace to define the container. This is because the namespace requires at least one `` element. In this environment, the listener is internal to the adapter. -For this reason, you must define the container using a normal Spring `` definition, such as: +For this reason, you must define the container by using a normal Spring `` definition, as the following example shows: + [source,xml] ---- - + ---- -===== +==== -IMPORTANT: Even though the Spring Integration JMS and AMQP support is very similar, important differences exist. -The JMS Inbound Channel Adapter is using a `JmsDestinationPollingSource` under the covers and expects a configured Poller. -The AMQP Inbound Channel Adapter uses an `AbstractMessageListenerContainer` and is message driven. -In that regard, it is more similar to the JMS Message Driven Channel Adapter. +IMPORTANT: Even though the Spring Integration JMS and AMQP support is similar, important differences exist. +The JMS inbound channel adapter is using a `JmsDestinationPollingSource` under the covers and expects a configured poller. +The AMQP inbound channel adapter uses an `AbstractMessageListenerContainer` and is message driven. +In that regard, it is more similar to the JMS message-driven channel adapter. ==== Configuring with Java Configuration -The following Spring Boot application provides an example of configuring the inbound adapter using Java configuration: +The following Spring Boot application shows an example of configuring the inbound adapter with Java configuration: + +==== [source, java] ---- @SpringBootApplication @@ -254,7 +207,7 @@ public class AmqpJavaApplication { public SimpleMessageListenerContainer container(ConnectionFactory connectionFactory) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); - container.setQueueNames("foo"); + container.setQueueNames("aName"); container.setConcurrentConsumers(2); // ... return container; @@ -275,11 +228,13 @@ public class AmqpJavaApplication { } ---- +==== ==== Configuring with the Java DSL -The following Spring Boot application provides an example of configuring the inbound adapter using the Java DSL: +The following Spring Boot application provides an example of configuring the inbound adapter with the Java DSL: +==== [source, java] ---- @SpringBootApplication @@ -293,21 +248,25 @@ public class AmqpJavaApplication { @Bean public IntegrationFlow amqpInbound(ConnectionFactory connectionFactory) { - return IntegrationFlows.from(Amqp.inboundAdapter(connectionFactory, "foo")) + return IntegrationFlows.from(Amqp.inboundAdapter(connectionFactory, "aName")) .handle(m -> System.out.println(m.getPayload())) .get(); } } ---- +==== === Polled Inbound Channel Adapter -Starting with _version 5.0.1_, a polled channel adapter is provided, allowing fetching individual messages on-demand, for example with a `MessageSourcePollingTemplate` or a poller. -See <> for more information. +Version 5.0.1 introduced a polled channel adapter, letting you fetch individual messages on demand -- for example, with a `MessageSourcePollingTemplate` or a poller. +See "`<>`" for more information. -It does not currently have XML configuration. +It does not currently support XML configuration. +The following example shows how to configure an `AmqpMessageSource` with Java configuration: + +==== [source, java] ---- @Bean @@ -315,11 +274,13 @@ public AmqpMessageSource source(ConnectionFactory connectionFactory) { return new AmpqpMessageSource(connectionFactory, "someQueue"); } ---- +==== -Refer to the javadocs for configuration properties. +See the https://docs.spring.io/spring-integration/api/org/springframework/integration/amqp/inbound/AmqpMessageSource.html[Javadoc] for configuration properties. -With the Java DSL: +The following example shows how to configure an `inboundPolledAdapter` with the Java DSL: +==== [source, java] ---- @Bean @@ -332,79 +293,67 @@ public IntegrationFlow flow() { .get(); } ---- +==== [[amqp-inbound-gateway]] === Inbound Gateway -The inbound gateway supports all the attributes on the inbound channel adapter (except 'channel' is replaced by 'request-channel'), plus some additional attributes: +The inbound gateway supports all the attributes on the inbound channel adapter (except that 'channel' is replaced by 'request-channel'), plus some additional attributes. +The following listing shows the available attributes: [source, xml] ---- + id="inboundGateway" <1> request-channel="myRequestChannel" <2> - header-mapper="" <3> - mapped-request-headers="" <4> - mapped-reply-headers="" <5> - reply-channel="myReplyChannel" <6> - reply-timeout="1000" <7> - amqp-template="" <8> - default-reply-to="" /> <9> + header-mapper="" <3> + mapped-request-headers="" <4> + mapped-reply-headers="" <5> + reply-channel="myReplyChannel" <6> + reply-timeout="1000" <7> + amqp-template="" <8> + default-reply-to="" /> <9> ---- -<1> Unique ID for this adapter. -_Optional_. - - -<2> Message Channel to which converted Messages should be sent. -_Required_. - - +<1> The Unique ID for this adapter. +Optional. +<2> Message channel to which converted messages are sent. +Required. <3> A reference to an `AmqpHeaderMapper` to use when receiving AMQP Messages. -_Optional_. -By default only standard AMQP properties (e.g. -`contentType`) will be copied to and from Spring Integration `MessageHeaders`. -Any user-defined headers within the AMQP `MessageProperties` will NOT be copied to or from an AMQP Message by the default `DefaultAmqpHeaderMapper`. +Optional. +By default, only standard AMQP properties (such as `contentType`) are copied to and from Spring Integration `MessageHeaders`. +Any user-defined headers within the AMQP `MessageProperties` are not copied to or from an AMQP message by the default `DefaultAmqpHeaderMapper`. Not allowed if 'request-header-names' or 'reply-header-names' is provided. - - <4> Comma-separated list of names of AMQP Headers to be mapped from the AMQP request into the `MessageHeaders`. -This can only be provided if the 'header-mapper' reference is not provided. -The values in this list can also be simple patterns to be matched against the header names (e.g. `"\*"` or `"foo*, bar"` or `"*foo"`). - - -<5> Comma-separated list of names of `MessageHeaders` to be mapped into the AMQP Message Properties of the AMQP reply message. -All standard Headers (e.g., `contentType`) will be mapped to AMQP Message Properties while user-defined headers will be mapped to the 'headers' property. -This can only be provided if the 'header-mapper' reference is not provided. -The values in this list can also be simple patterns to be matched against the header names (e.g. `"\*"` or `"foo*, bar"` or `"*foo"`). - - -<6> Message Channel where reply Messages will be expected. -_Optional_. - - -<7> Used to set the `receiveTimeout` on the underlying `org.springframework.integration.core.MessagingTemplate` for receiving messages from the reply channel. -If not specified this property will default to "1000" (1 second). +This attribute can be provided only if the 'header-mapper' reference is not provided. +The values in this list can also be simple patterns to be matched against the header names (e.g. `"\*"` or `"thing1*, thing2"` or `"*thing1"`). +<5> Comma-separated list of names of `MessageHeaders` to be mapped into the AMQP message properties of the AMQP reply message. +All standard Headers (such as `contentType`) are mapped to AMQP Message Properties, while user-defined headers are mapped to the 'headers' property. +This attribute can only be provided if the 'header-mapper' reference is not provided. +The values in this list can also be simple patterns to be matched against the header names (for example, `"\*"` or `"foo*, bar"` or `"*foo"`). +<6> Message Channel where reply Messages are expected. +Optional. +<7> Sets the `receiveTimeout` on the underlying `o.s.i.core.MessagingTemplate` for receiving messages from the reply channel. +If not specified, this property defaults to `1000` (1 second). Only applies if the container thread hands off to another thread before the reply is sent. - -<8> The customized `AmqpTemplate` bean reference to have more control for the reply messages to send or you can provide -an alternative implementation to the `RabbitTemplate`. - -<9> The `replyTo` `org.springframework.amqp.core.Address` to be used when the `requestMessage` doesn't have `replyTo` +<8> The customized `AmqpTemplate` bean reference (to have more control over the reply messages to send). +You can provide an alternative implementation to the `RabbitTemplate`. +<9> The `replyTo` `o.s.amqp.core.Address` to be used when the `requestMessage` does not have a `replyTo` property. -If this option isn't specified, no `amqp-template` is provided, and no `replyTo` property exists in the request message, -an `IllegalStateException` is thrown because the reply can't be routed. -If this option isn't specified, and an external `amqp-template` is provided, no exception will be thrown. -You __must__ either specify this option, or configure a default `exchange` and `routingKey` on that template, +If this option is not specified, no `amqp-template` is provided, no `replyTo` property exists in the request message, and +an `IllegalStateException` is thrown because the reply cannot be routed. +If this option is not specified and an external `amqp-template` is provided, no exception is thrown. +You must either specify this option or configure a default `exchange` and `routingKey` on that template, if you anticipate cases when no `replyTo` property exists in the request message. -See the note in <> about configuring the `listener-container` attribute. +See the note in "`<>`" about configuring the `listener-container` attribute. ==== Configuring with Java Configuration -The following Spring Boot application provides an example of configuring the inbound gateway using Java configuration: +The following Spring Boot application shows an example of how to configure the inbound gateway with Java configuration: +==== [source, java] ---- @SpringBootApplication @@ -455,11 +404,13 @@ public class AmqpJavaApplication { } ---- +==== ==== Configuring with the Java DSL -The following Spring Boot application provides an example of configuring the inbound gateway using the Java DSL: +The following Spring Boot application shows an example of how to configure the inbound gateway with the Java DSL: +==== [source, java] ---- @SpringBootApplication @@ -480,22 +431,24 @@ public class AmqpJavaApplication { } ---- +==== [[amqp-inbound-ack]] === Inbound Endpoint Acknowledge Mode -By default the inbound endpoints use acknowledge mode `AUTO`, which means the container automatically _acks_ the message when the downstream integration flow completes (or a message is handed off to another thread using a `QueueChannel` or `ExecutorChannel`). -Setting the mode to `NONE` configures the consumer such that acks are not used at all (the broker automatically acks the message as soon as it is sent). -Setting the mode to `MANUAL` allows user code to ack the message at some other point during processing. -To support this, with this mode, the endpoints provide the `Channel` and `deliveryTag` in the `amqp_channel` and `amqp_deliveryTag` headers respectively. +By default, the inbound endpoints use the `AUTO` acknowledge mode, which means the container automatically acknowledges the message when the downstream integration flow completes (or a message is handed off to another thread by using a `QueueChannel` or `ExecutorChannel`). +Setting the mode to `NONE` configures the consumer such that acknowledgments are not used at all (the broker automatically acknowledges the message as soon as it is sent). +Setting the mode to `MANUAL` lets user code acknowledge the message at some other point during processing. +To support this, with this mode, the endpoints provide the `Channel` and `deliveryTag` in the `amqp_channel` and `amqp_deliveryTag` headers, respectively. -You can perform any valid rabbit command on the `Channel` but, generally, only `basicAck` and `basicNack` (or `basicReject`) would be used. -In order to not interfere with the operation of the container, you should not retain a reference to the channel and just use it in the context of the current message. +You can perform any valid Rabbit command on the `Channel` but, generally, only `basicAck` and `basicNack` (or `basicReject`) are used. +In order to not interfere with the operation of the container, you should not retain a reference to the channel and use it only in the context of the current message. -NOTE: Since the `Channel` is a reference to a "live" object, it cannot be serialized and will be lost if a message is persisted. +NOTE: Since the `Channel` is a reference to a "`live`" object, it cannot be serialized and is lost if a message is persisted. -This is an example of how you might use `MANUAL` acknowledgement: +The following example shows how you might use `MANUAL` acknowledgement: +==== [source,java] ---- @ServiceActivator(inputChannel = "foo", outputChannel = "bar") @@ -516,143 +469,120 @@ public Object handle(@Payload String payload, @Header(AmqpHeaders.CHANNEL) Chann return someResultForDownStreamProcessing; } ---- +==== [[amqp-outbound-channel-adapter]] === Outbound Channel Adapter -A configuration sample for an AMQP Outbound Channel Adapter is shown below. +The following example shows the available properties for an AMQP outbound channel adapter: +==== [source,xml] ---- - - channel="outboundChannel" <2> - amqp-template="myAmqpTemplate" <3> - exchange-name="" <4> - exchange-name-expression="" <5> - order="1" <6> - routing-key="" <7> - routing-key-expression="" <8> - default-delivery-mode"" <9> + + channel="outboundChannel" <2> + amqp-template="myAmqpTemplate" <3> + exchange-name="" <4> + exchange-name-expression="" <5> + order="1" <6> + routing-key="" <7> + routing-key-expression="" <8> + default-delivery-mode"" <9> confirm-correlation-expression="" <10> - confirm-ack-channel="" <11> - confirm-nack-channel="" <12> - return-channel="" <13> - error-message-strategy="" <14> - header-mapper="" <15> - mapped-request-headers="" <16> - lazy-connect="true" /> <17> + confirm-ack-channel="" <11> + confirm-nack-channel="" <12> + return-channel="" <13> + error-message-strategy="" <14> + header-mapper="" <15> + mapped-request-headers="" <16> + lazy-connect="true" /> <17> ---- -<1> Unique ID for this adapter. -_Optional_. - - -<2> Message Channel to which Messages should be sent in order to have them converted and published to an AMQP Exchange. -_Required_. - - -<3> Bean Reference to the configured AMQP Template _Optional (Defaults to "amqpTemplate")_. - - -<4> The name of the AMQP Exchange to which Messages should be sent. -If not provided, Messages will be sent to the default, no-name Exchange. +<1> The unique ID for this adapter. +Optional. +<2> Message channel to which messages should be sent to have them converted and published to an AMQP exchange. +Required. +<3> Bean reference to the configured AMQP template. +Optional (defaults to `amqpTemplate`). +<4> The name of the AMQP exchange to which messages are sent. +If not provided, messages are sent to the default, no-name exchange. Mutually exclusive with 'exchange-name-expression'. -_Optional_. - - -<5> A SpEL expression that is evaluated to determine the name of the AMQP Exchange to which Messages should be sent, with the message as the root object. -If not provided, Messages will be sent to the default, no-name Exchange. +Optional. +<5> A SpEL expression that is evaluated to determine the name of the AMQP exchange to which messages are sent, with the message as the root object. +If not provided, messages are sent to the default, no-name exchange. Mutually exclusive with 'exchange-name'. -_Optional_. - - -<6> The order for this consumer when multiple consumers are registered thereby enabling load-balancing and/or failover. -_Optional (Defaults to Ordered.LOWEST_PRECEDENCE [=Integer.MAX_VALUE])_. - - -<7> The fixed routing-key to use when sending Messages. -By default, this will be an empty String. -Mutually exclusive with 'routing-key-expression'._Optional_. - - -<8> A SpEL expression that is evaluated to determine the routing-key to use when sending Messages, with the message as the root object (e.g. -'payload.key'). -By default, this will be an empty String. +Optional. +<6> The order for this consumer when multiple consumers are registered, thereby enabling load-balancing and failover. +Optional (defaults to `Ordered.LOWEST_PRECEDENCE [=Integer.MAX_VALUE]`). +<7> The fixed routing-key to use when sending messages. +By default, this is an empty `String`. +Mutually exclusive with 'routing-key-expression'. +Optional. +<8> A SpEL expression that is evaluated to determine the routing key to use when sending messages, with the message as the root object (for example, 'payload.key'). +By default, this is an empty `String`. Mutually exclusive with 'routing-key'. -_Optional_. - - -<9> The default delivery mode for messages; `PERSISTENT` or `NON_PERSISTENT`. +Optional. +<9> The default delivery mode for messages: `PERSISTENT` or `NON_PERSISTENT`. Overridden if the `header-mapper` sets the delivery mode. -The `DefaultHeaderMapper` sets the value if the Spring Integration message header `amqp_deliveryMode` is present. -If this attribute is not supplied and the header mapper doesn't set it, the default depends on the underlying -spring-amqp `MessagePropertiesConverter` used by the `RabbitTemplate`. +If the Spring Integration message header `amqp_deliveryMode` is present, the `DefaultHeaderMapper` sets the value. +If this attribute is not supplied and the header mapper does not set it, the default depends on the underlying Spring AMQP `MessagePropertiesConverter` used by the `RabbitTemplate`. If that is not customized at all, the default is `PERSISTENT`. -_Optional_. - - -<10> An expression defining correlation data. -When provided, this configures the underlying amqp template to receive publisher confirms. +Optional. +<10> An expression that defines correlation data. +When provided, this configures the underlying AMQP template to receive publisher confirmations. Requires a dedicated `RabbitTemplate` and a `CachingConnectionFactory` with the `publisherConfirms` property set to -`true`. When a publisher confirm is received, and correlation data is supplied, it is written to either the -confirm-ack-channel, or the confirm-nack-channel, depending on the confirmation type. The payload of the confirm is -the correlation data as defined by this expression and the message will have a header 'amqp_publishConfirm' set to true (ack) or false (nack). -Examples: "`headers['myCorrelationData']`", "`payload`". -Starting with _version 4.1_ the `amqp_publishConfirmNackCause` message header has been added. -It contains the `cause` of a 'nack' for publisher confirms. -Starting with _version 4.2_, if the expression resolves to a `Message` instance (such as "`#this`"), the message -emitted on the ack/nack channel is based on that message, with the additional header(s) added. +`true`. When a publisher confirmation is received and correlation data is supplied, it is written to either the +`confirm-ack-channel` or the `confirm-nack-channel`, depending on the confirmation type. The payload of the confirmation is +the correlation data, as defined by this expression. +The message has an 'amqp_publishConfirm' header set to `true` (`ack`) or `false` (`nack`). +Examples: `headers['myCorrelationData']` and `payload`. +Version 4.1 introduced the `amqp_publishConfirmNackCause` message header. +It contains the `cause` of a 'nack' for a publisher confirmation. +Starting with version 4.2, if the expression resolves to a `Message` instance (such as `#this`), the message +emitted on the `ack`/`nack` channel is based on that message, with the additional header(s) added. Previously, a new message was created with the correlation data as its payload, regardless of type. -_Optional_. - -<11> The channel to which positive (ack) publisher confirms are sent; payload is the correlation data defined by the _confirm-correlation-expression_. +Optional. +<11> The channel to which positive (`ack`) publisher confirms are sent. +The payload is the correlation data defined by the `confirm-correlation-expression`. If the expression is `#root` or `#this`, the message is built from the original message, with the `amqp_publishConfirm` header set to `true`. -_Optional, default=nullChannel_. - - -<12> The channel to which negative (nack) publisher confirms are sent; payload is the correlation data defined by the _confirm-correlation-expression_ (if there is no `ErrorMessageStrategy` configured). +Optional (the default is `nullChannel`). +<12> The channel to which negative (`nack`) publisher confirmations are sent. +The payload is the correlation data defined by the `confirm-correlation-expression` (if there is no `ErrorMessageStrategy` configured). If the expression is `#root` or `#this`, the message is built from the original message, with the `amqp_publishConfirm` header set to `false`. -When there is an `ErrorMessageStrategy`, the message will be an `ErrorMessage` with a `NackedAmqpMessageException` payload. -_Optional, default=nullChannel_. - - +When there is an `ErrorMessageStrategy`, the message is an `ErrorMessage` with a `NackedAmqpMessageException` payload. +Optional (the default is `nullChannel`). <13> The channel to which returned messages are sent. -When provided, the underlying amqp template is configured to return undeliverable messages to the adapter. -When there is no `ErrorMessageStrategy` configured, the message will be constructed from the data received from amqp, with the following additional headers: _amqp_returnReplyCode, amqp_returnReplyText, amqp_returnExchange, amqp_returnRoutingKey_. -When there is an `ErrorMessageStrategy`, the message will be an `ErrorMessage` with a `ReturnedAmqpMessageException` payload. -_Optional_. - -<14> A reference to an `ErrorMessageStrategy` implementation used to build `ErrorMessage` s when sending returned or negatively acknowedged messages. - +When provided, the underlying AMQP template is configured to return undeliverable messages to the adapter. +When there is no `ErrorMessageStrategy` configured, the message is constructed from the data received from AMQP, with the following additional headers: `amqp_returnReplyCode`, `amqp_returnReplyText`, `amqp_returnExchange`, `amqp_returnRoutingKey`. +When there is an `ErrorMessageStrategy`, the message is an `ErrorMessage` with a `ReturnedAmqpMessageException` payload. +Optional. +<14> A reference to an `ErrorMessageStrategy` implementation used to build `ErrorMessage` instances when sending returned or negatively acknowledged messages. <15> A reference to an `AmqpHeaderMapper` to use when sending AMQP Messages. -By default only standard AMQP properties (e.g. -`contentType`) will be copied to the Spring Integration `MessageHeaders`. -Any user-defined headers will NOT be copied to the Message by the default`DefaultAmqpHeaderMapper`. +By default, only standard AMQP properties (such as `contentType`) are copied to the Spring Integration `MessageHeaders`. +Any user-defined headers is not copied to the message by the default`DefaultAmqpHeaderMapper`. Not allowed if 'request-header-names' is provided. -_Optional_. - - +Optional. <16> Comma-separated list of names of AMQP Headers to be mapped from the `MessageHeaders` to the AMQP Message. Not allowed if the 'header-mapper' reference is provided. -The values in this list can also be simple patterns to be matched against the header names (e.g. `"\*"` or `"foo*, bar"` or `"*foo"`). - - -<17> When set to `false`, the endpoint will attempt to connect to the broker during application context initialization. -This allows "fail fast" detection of bad configuration, but will also cause initialization to fail if the broker is down. -When true (default), the connection is established (if it doesn't already exist because some other component established it) when the first message is sent. - +The values in this list can also be simple patterns to be matched against the header names (e.g. `"\*"` or `"thing1*, thing2"` or `"*thing1"`). +<17> When set to `false`, the endpoint attempts to connect to the broker during application context initialization. +This allows "`fail fast`" detection of bad configuration but also causes initialization to fail if the broker is down. +When `true` (the default), the connection is established (if it does not already exist because some other component established it) when the first message is sent. +==== [IMPORTANT] .return-channel ===== -Using a `return-channel` requires a `RabbitTemplate` with the `mandatory` property set to `true`, and a `CachingConnectionFactory` with the `publisherReturns` property set to `true`. +Using a `return-channel` requires a `RabbitTemplate` with the `mandatory` property set to `true` and a `CachingConnectionFactory` with the `publisherReturns` property set to `true`. When using multiple outbound endpoints with returns, a separate `RabbitTemplate` is needed for each endpoint. ===== ==== Configuring with Java Configuration -The following Spring Boot application provides an example of configuring the outbound adapter using Java configuration: +The following Spring Boot application shows an example of how to configure the outbound adapter with Java configuration: + +==== [source, java] ---- @SpringBootApplication @@ -690,11 +620,13 @@ public class AmqpJavaApplication { } ---- +==== ==== Configuring with the Java DSL -The following Spring Boot application provides an example of configuring the outbound adapter using the Java DSL: +The following Spring Boot application shows an example of how to configure the outbound adapter with the Java DSL: +==== [source, java] ---- @SpringBootApplication @@ -731,143 +663,122 @@ public class AmqpJavaApplication { } } ---- +==== [[amqp-outbound-gateway]] === Outbound Gateway -Configuration for an AMQP Outbound Gateway is shown below. +The following listing shows the possible properties for an AMQP Outbound Gateway: +==== [source,xml] ---- - + request-channel="myRequestChannel" <2> - amqp-template="" <3> - exchange-name="" <4> - exchange-name-expression="" <5> - order="1" <6> - reply-channel="" <7> - reply-timeout="" <8> - requires-reply="" <9> - routing-key="" <10> - routing-key-expression="" <11> - default-delivery-mode"" <12> - confirm-correlation-expression="" <13> - confirm-ack-channel="" <14> - confirm-nack-channel="" <15> - return-channel="" <16> - error-message-strategy="" <17> - lazy-connect="true" /> <18> + amqp-template="" <3> + exchange-name="" <4> + exchange-name-expression="" <5> + order="1" <6> + reply-channel="" <7> + reply-timeout="" <8> + requires-reply="" <9> + routing-key="" <10> + routing-key-expression="" <11> + default-delivery-mode"" <12> + confirm-correlation-expression="" <13> + confirm-ack-channel="" <14> + confirm-nack-channel="" <15> + return-channel="" <16> + error-message-strategy="" <17> + lazy-connect="true" /> <18> ---- -<1> Unique ID for this adapter. -_Optional_. - - -<2> Message Channel to which Messages should be sent in order to have them converted and published to an AMQP Exchange. -_Required_. - - -<3> Bean Reference to the configured AMQP Template _Optional (Defaults to "amqpTemplate")_. - - -<4> The name of the AMQP Exchange to which Messages should be sent. -If not provided, Messages will be sent to the default, no-name Exchange. +<1> The unique ID for this adapter. +Optional. +<2> Message channel to which messages are sent to have them converted and published to an AMQP exchange. +Required. +<3> Bean reference to the configured AMQP template. +Optional (defaults to `amqpTemplate`). +<4> The name of the AMQP exchange to which messages should be sent. +If not provided, messages are sent to the default, no-name cxchange. Mutually exclusive with 'exchange-name-expression'. -_Optional_. - - -<5> A SpEL expression that is evaluated to determine the name of the AMQP Exchange to which Messages should be sent, with the message as the root object. -If not provided, Messages will be sent to the default, no-name Exchange. +Optional. +<5> A SpEL expression that is evaluated to determine the name of the AMQP exchange to which messages should be sent, with the message as the root object. +If not provided, messages are sent to the default, no-name exchange. Mutually exclusive with 'exchange-name'. -_Optional_. - - -<6> The order for this consumer when multiple consumers are registered thereby enabling load-balancing and/or failover. -_Optional (Defaults to Ordered.LOWEST_PRECEDENCE [=Integer.MAX_VALUE])_. - - -<7> Message Channel to which replies should be sent after being received from an AMQP Queue and converted._Optional_. - - -<8> The time the gateway will wait when sending the reply message to the `reply-channel`. -This only applies if the `reply-channel` can block - such as a `QueueChannel` with a capacity limit that is currently full. -Default: infinity. - - -<9> When `true`, the gateway will throw an exception if no reply message is received within the `AmqpTemplate`'s `replyTimeout` property. -Default: `true`. - - -<10> The routing-key to use when sending Messages. -By default, this will be an empty String. +Optional. +<6> The order for this consumer when multiple consumers are registered, thereby enabling load-balancing and failover. +Optional (defaults to `Ordered.LOWEST_PRECEDENCE [=Integer.MAX_VALUE]`). +<7> Message channel to which replies should be sent after being received from an AMQP queue and converted. +Optional. +<8> The time the gateway waits when sending the reply message to the `reply-channel`. +This only applies if the `reply-channel` can block -- such as a `QueueChannel` with a capacity limit that is currently full. +Defaults to infinity. +<9> When `true`, the gateway throws an exception if no reply message is received within the `AmqpTemplate`'s `replyTimeout` property. +Defaults to `true`. +<10> The `routing-key` to use when sending messages. +By default, this is an empty `String`. Mutually exclusive with 'routing-key-expression'. -_Optional_. - - -<11> A SpEL expression that is evaluated to determine the routing-key to use when sending Messages, with the message as the root object (e.g. -'payload.key'). -By default, this will be an empty String. +Optional. +<11> A SpEL expression that is evaluated to determine the `routing-key` to use when sending messages, with the message as the root object (for example, 'payload.key'). +By default, this is an empty `String`. Mutually exclusive with 'routing-key'. -_Optional_. - - -<12> The default delivery mode for messages; `PERSISTENT` or `NON_PERSISTENT`. +Optional. +<12> The default delivery mode for messages: `PERSISTENT` or `NON_PERSISTENT`. Overridden if the `header-mapper` sets the delivery mode. -The `DefaultHeaderMapper` sets the value if the Spring Integration message header `amqp_deliveryMode` is present. -If this attribute is not supplied and the header mapper doesn't set it, the default depends on the underlying -spring-amqp `MessagePropertiesConverter` used by the `RabbitTemplate`. +If the Spring Integration message header `amqp_deliveryMode` is present, the `DefaultHeaderMapper` sets the value. +If this attribute is not supplied and the header mapper does not set it, the default depends on the underlying Spring AMQP `MessagePropertiesConverter` used by the `RabbitTemplate`. If that is not customized at all, the default is `PERSISTENT`. -_Optional_. - -<13> Since _version 4.2_. An expression defining correlation data. -When provided, this configures the underlying amqp template to receive publisher confirms. -Requires a dedicated `RabbitTemplate` and a `CachingConnectionFactory` with the `publisherConfirms` property set to -`true`. When a publisher confirm is received, and correlation data is supplied, it is written to either the -confirm-ack-channel, or the confirm-nack-channel, depending on the confirmation type. The payload of the confirm is -the correlation data as defined by this expression and the message will have a header 'amqp_publishConfirm' set to true (ack) or false (nack). -For nacks, an additional header `amqp_publishConfirmNackCause` is provided. -Examples: "headers['myCorrelationData']", "payload". -If the expression resolves to a `Message` instance (such as "`#this`"), the message -emitted on the ack/nack channel is based on that message, with the additional header(s) added. +Optional. +<13> Since version 4.2. +An expression defining correlation data. +When provided, this configures the underlying AMQP template to receive publisher confirms. +Requires a dedicated `RabbitTemplate` and a `CachingConnectionFactory` with the `publisherConfirms` property set to `true`. +When a publisher confirm is received and correlation data is supplied, it is written to either the `confirm-ack-channel` or the `confirm-nack-channel`, depending on the confirmation type. +The payload of the confirm is the correlation data, as defined by this expression. +The message has a header 'amqp_publishConfirm' set to `true` (`ack`) or `false` (`nack`). +For `nack` confirmations, Spring Integration provides an additional header `amqp_publishConfirmNackCause`. +Examples: `headers['myCorrelationData']` and `payload`. +If the expression resolves to a `Message` instance (such as `#this`), the message +emitted on the `ack`/`nack` channel is based on that message, with the additional headers added. Previously, a new message was created with the correlation data as its payload, regardless of type. -_Optional_. - -<14> The channel to which positive (ack) publisher confirms are sent; payload is the correlation data defined by the _confirm-correlation-expression_. +Optional. +<14> The channel to which positive (`ack`) publisher confirmations are sent. +The payload is the correlation data defined by `confirm-correlation-expression`. If the expression is `#root` or `#this`, the message is built from the original message, with the `amqp_publishConfirm` header set to `true`. -_Optional, default=nullChannel_. - -<15> The channel to which negative (nack) publisher confirms are sent; payload is the correlation data defined by the _confirm-correlation-expression_ (if there is no `ErrorMessageStrategy` configured). +Optional (the default is `nullChannel`). +<15> The channel to which negative (`nack`) publisher confirmations are sent. +The payload is the correlation data defined by `confirm-correlation-expression` (if there is no `ErrorMessageStrategy` configured). If the expression is `#root` or `#this`, the message is built from the original message, with the `amqp_publishConfirm` header set to `false`. -When there is an `ErrorMessageStrategy`, the message will be an `ErrorMessage` with a `NackedAmqpMessageException` payload. -_Optional, default=nullChannel_. - +When there is an `ErrorMessageStrategy`, the message is an `ErrorMessage` with a `NackedAmqpMessageException` payload. +Optional (the default is `nullChannel`). <16> The channel to which returned messages are sent. -When provided, the underlying amqp template is configured to return undeliverable messages to the adapter. -When there is no `ErrorMessageStrategy` configured, the message will be constructed from the data received from amqp, with the following additional headers: _amqp_returnReplyCode, amqp_returnReplyText, amqp_returnExchange, amqp_returnRoutingKey_. -When there is an `ErrorMessageStrategy`, the message will be an `ErrorMessage` with a `ReturnedAmqpMessageException` payload. -_Optional_. - -<17> A reference to an `ErrorMessageStrategy` implementation used to build `ErrorMessage` s when sending returned or negatively acknowedged messages. - -<18> When set to `false`, the endpoint will attempt to connect to the broker during application context initialization. -This allows "fail fast" detection of bad configuration, by logging an error message if the broker is down. -When true (default), the connection is established (if it doesn't already exist because some other component established it) when the first message is sent. - +When provided, the underlying AMQP template is configured to return undeliverable messages to the adapter. +When there is no `ErrorMessageStrategy` configured, the message is constructed from the data received from AMQP, with the following additional headers: `amqp_returnReplyCode`, `amqp_returnReplyText`, `amqp_returnExchange`, and `amqp_returnRoutingKey`. +When there is an `ErrorMessageStrategy`, the message is an `ErrorMessage` with a `ReturnedAmqpMessageException` payload. +Optional. +<17> A reference to an `ErrorMessageStrategy` implementation used to build `ErrorMessage` instances when sending returned or negatively acknowledged messages. +<18> When set to `false`, the endpoint attempts to connect to the broker during application context initialization. +This allows "`fail fast`" detection of bad configuration by logging an error message if the broker is down. +When `true` (the default), the connection is established (if it does not already exist because some other component established it) when the first message is sent. +==== [IMPORTANT] .return-channel ===== -Using a `return-channel` requires a `RabbitTemplate` with the `mandatory` property set to `true`, and a `CachingConnectionFactory` with the `publisherReturns` property set to `true`. +Using a `return-channel` requires a `RabbitTemplate` with the `mandatory` property set to `true` and a `CachingConnectionFactory` with the `publisherReturns` property set to `true`. When using multiple outbound endpoints with returns, a separate `RabbitTemplate` is needed for each endpoint. ===== -IMPORTANT: The underlying `AmqpTemplate` has a default `replyTimeout` of 5 seconds. -If you require a longer timeout, it must be configured on the `template`. +IMPORTANT: The underlying `AmqpTemplate` has a default `replyTimeout` of five seconds. +If you require a longer timeout, you must configure it on the `template`. ==== Configuring with Java Configuration -The following Spring Boot application provides an example of configuring the outbound gateway using Java configuration: +The following Spring Boot application shows an example of how to configure the outbound gateway with Java configuration: + +==== [source, java] ---- @SpringBootApplication @@ -907,14 +818,16 @@ public class AmqpJavaApplication { } ---- +==== -Notice that the only difference between the outbound adapter and outbound gateway configuration is the setting of the +Note that the only difference between the outbound adapter and outbound gateway configuration is the setting of the `expectReply` property. ==== Configuring with the Java DSL -The following Spring Boot application provides an example of configuring the outbound adapter using the Java DSL: +The following Spring Boot application shows an example of how to configure the outbound adapter with the Java DSL: +==== [source, java] ---- @SpringBootApplication @@ -953,20 +866,21 @@ public class AmqpJavaApplication { } } ---- +==== [[amqp-async-outbound-gateway]] -=== Async Outbound Gateway +=== Asynchronous Outbound Gateway The gateway discussed in the previous section is synchronous, in that the sending thread is suspended until a reply is received (or a timeout occurs). -Spring Integration _version 4.3_ added this asynchronous gateway, which uses the `AsyncRabbitTemplate` from Spring AMQP. -When a message is sent, the thread returns immediately after the send completes, and the reply is sent on the template's -listener container thread when it is received. -This can be useful when the gateway is invoked on a poller thread; the thread is released and is available for other -tasks in the framework. +Spring Integration version 4.3 added an asynchronous gateway, which uses the `AsyncRabbitTemplate` from Spring AMQP. +When a message is sent, the thread returns immediately after the send operation completes, and, when the message is received, the reply is sent on the template's listener container thread. +This can be useful when the gateway is invoked on a poller thread. +The thread is released and is available for other tasks in the framework. -Configuration for an AMQP Async Outbound Gateway is shown below. +The following listing shows the possible configuration options for an AMQP asynchronous outbound gateway: +==== [source,xml] ---- @@ -989,114 +903,91 @@ Configuration for an AMQP Async Outbound Gateway is shown below. ---- -<1> Unique ID for this adapter. -_Optional_. - - -<2> Message Channel to which Messages should be sent in order to have them converted and published to an AMQP Exchange. -_Required_. - - -<3> Bean Reference to the configured `AsyncRabbitTemplate` _Optional (Defaults to "asyncRabbitTemplate")_. - - -<4> The name of the AMQP Exchange to which Messages should be sent. -If not provided, Messages will be sent to the default, no-name Exchange. +<1> The unique ID for this adapter. +Optional. +<2> Message channel to which messages should be sent in order to have them converted and published to an AMQP exchange. +Required. +<3> Bean reference to the configured `AsyncRabbitTemplate`. +Optional (it defaults to `asyncRabbitTemplate`). +<4> The name of the AMQP exchange to which messages should be sent. +If not provided, messages are sent to the default, no-name exchange. Mutually exclusive with 'exchange-name-expression'. -_Optional_. - - -<5> A SpEL expression that is evaluated to determine the name of the AMQP Exchange to which Messages should be sent, -with the message as the root object. -If not provided, Messages will be sent to the default, no-name Exchange. +Optional. +<5> A SpEL expression that is evaluated to determine the name of the AMQP exchange to which messages are sent, with the message as the root object. +If not provided, messages are sent to the default, no-name exchange. Mutually exclusive with 'exchange-name'. -_Optional_. - - -<6> The order for this consumer when multiple consumers are registered thereby enabling load-balancing and/or failover. -_Optional (Defaults to Ordered.LOWEST_PRECEDENCE [=Integer.MAX_VALUE])_. - - -<7> Message Channel to which replies should be sent after being received from an AMQP Queue and converted. _Optional_. - - -<8> The time the gateway will wait when sending the reply message to the `reply-channel`. -This only applies if the `reply-channel` can block - such as a `QueueChannel` with a capacity limit that is currently full. -Default: infinity. - -<9> When `true`, the gateway will send an error message to the inbound message's `errorChannel` header, -if present or otherwise to the default `errorChannel` (if available), when no reply -message is received within the `AsyncRabbitTemplate`'s `receiveTimeout` property. Default: `true`. - +Optional. +<6> The order for this consumer when multiple consumers are registered, thereby enabling load-balancing and failover. +Optional (it defaults to `Ordered.LOWEST_PRECEDENCE [=Integer.MAX_VALUE]`). +<7> Message channel to which replies should be sent after being received from an AMQP queue and converted. +Optional. +<8> The time the gateway waits when sending the reply message to the `reply-channel`. +This only applies if the `reply-channel` can block -- such as a `QueueChannel` with a capacity limit that is currently full. +The default is infinity. +<9> When no reply message is received within the `AsyncRabbitTemplate`'s `receiveTimeout` property and this setting is `true`, the gateway sends an error message to the inbound message's `errorChannel` header. +When no reply message is received within the `AsyncRabbitTemplate`'s `receiveTimeout` property and this setting is `false`, the gateway sends an error message to the default `errorChannel` (if available). +It defaults to `true`. <10> The routing-key to use when sending Messages. -By default, this will be an empty String. +By default, this is an empty `String`. Mutually exclusive with 'routing-key-expression'. -_Optional_. - - -<11> A SpEL expression that is evaluated to determine the routing-key to use when sending Messages, -with the message as the root object (e.g. 'payload.key'). -By default, this will be an empty String. +Optional. +<11> A SpEL expression that is evaluated to determine the routing-key to use when sending messages, +with the message as the root object (for example, 'payload.key'). +By default, this is an empty `String`. Mutually exclusive with 'routing-key'. -_Optional_. - - -<12> The default delivery mode for messages; `PERSISTENT` or `NON_PERSISTENT`. +Optional. +<12> The default delivery mode for messages: `PERSISTENT` or `NON_PERSISTENT`. Overridden if the `header-mapper` sets the delivery mode. -The `DefaultHeaderMapper` sets the value if the Spring Integration message header `amqp_deliveryMode` is present. -If this attribute is not supplied and the header mapper doesn't set it, the default depends on the underlying -spring-amqp `MessagePropertiesConverter` used by the `RabbitTemplate`. -If that is not customized at all, the default is `PERSISTENT`. -_Optional_. - -<13> An expression defining correlation data. -When provided, this configures the underlying amqp template to receive publisher confirms. -Requires a dedicated `RabbitTemplate` and a `CachingConnectionFactory` with the `publisherConfirms` property set to -`true`. When a publisher confirm is received, and correlation data is supplied, it is written to either the -confirm-ack-channel, or the confirm-nack-channel, depending on the confirmation type. The payload of the confirm is -the correlation data as defined by this expression and the message will have a header 'amqp_publishConfirm' set to true -(ack) or false (nack). -For nacks, an additional header `amqp_publishConfirmNackCause` is provided. -Examples: "headers['myCorrelationData']", "payload". +If the Spring Integration message header (`amqp_deliveryMode`) is present, the `DefaultHeaderMapper` sets the value. +If this attribute is not supplied and the header mapper does not set it, the default depends on the underlying Spring AMQP `MessagePropertiesConverter` used by the `RabbitTemplate`. +If that is not customized, the default is `PERSISTENT`. +Optional. +<13> An expression that defines correlation data. +When provided, this configures the underlying AMQP template to receive publisher confirmations. +Requires a dedicated `RabbitTemplate` and a `CachingConnectionFactory` with its `publisherConfirms` property set to +`true`. When a publisher confirmation is received and correlation data is supplied, the confirmation is written to either the +`confirm-ack-channel` or the `confirm-nack-channel`, depending on the confirmation type. The payload of the confirmation is +the correlation data as defined by this expression, and the message has its 'amqp_publishConfirm' header set to `true` +(`ack`) or `false` (`nack`). +For `nack` instances, an additional header (`amqp_publishConfirmNackCause`) is provided. +Examples: `headers['myCorrelationData']`, `payload`. If the expression resolves to a `Message` instance (such as "`#this`"), the message -emitted on the ack/nack channel is based on that message, with the additional header(s) added. -_Optional_. - -<14> The channel to which positive (ack) publisher confirms are sent; payload is the correlation -data defined by the _confirm-correlation-expression_. -Requires the underlying `AsyncRabbitTemplate` to have its `enableConfirms` property set to true. -_Optional, default=nullChannel_. - -<15> Since _version 4.2_. The channel to which negative (nack) publisher confirms are sent; payload is the correlation -data defined by the _confirm-correlation-expression_. -Requires the underlying `AsyncRabbitTemplate` to have its `enableConfirms` property set to true. -_Optional, default=nullChannel_. - +emitted on the `ack`/`nack` channel is based on that message, with the additional headers added. +Optional. +<14> The channel to which positive (`ack`) publisher confirmations are sent. +The payload is the correlation data defined by the `confirm-correlation-expression`. +Requires the underlying `AsyncRabbitTemplate` to have its `enableConfirms` property set to `true`. +Optional (the default is `nullChannel`). +<15> Since version 4.2. The channel to which negative (`nack`) publisher confirmations are sent. +The payload is the correlation data defined by the `confirm-correlation-expression`. +Requires the underlying `AsyncRabbitTemplate` to have its `enableConfirms` property set to `true`. +Optional (the default is `nullChannel`). <16> The channel to which returned messages are sent. -When provided, the underlying amqp template is configured to return undeliverable messages to the gateway. -The message will be constructed from the data received from amqp, with the following additional headers: -_amqp_returnReplyCode, amqp_returnReplyText, amqp_returnExchange, amqp_returnRoutingKey_. -Requires the underlying `AsyncRabbitTemplate` to have its `mandatory` property set to true. -_Optional_. - -<17> When set to `false`, the endpoint will attempt to connect to the broker during application context initialization. -This allows "fail fast" detection of bad configuration, by logging an error message if the broker is down. -When true (default), the connection is established (if it doesn't already exist because some other component established +When provided, the underlying AMQP template is configured to return undeliverable messages to the gateway. +The message is constructed from the data received from AMQP, with the following additional headers: +`amqp_returnReplyCode`, `amqp_returnReplyText`, `amqp_returnExchange`, and `amqp_returnRoutingKey`. +Requires the underlying `AsyncRabbitTemplate` to have its `mandatory` property set to `true`. +Optional. +<17> When set to `false`, the endpoint tries to connect to the broker during application context initialization. +Doing so allows "`fail fast`" detection of bad configuration, by logging an error message if the broker is down. +When `true` (the default), the connection is established (if it does not already exist because some other component established it) when the first message is sent. +==== -Also see <> for more information. +See also "`<>`" for more information. [IMPORTANT] .RabbitTemplate ===== -When using confirms and returns, it is recommended that the `RabbitTemplate` wired into the `AsyncRabbitTemplate` be -dedicated. +When you use confirmations and returns, we recommend that the `RabbitTemplate` wired into the `AsyncRabbitTemplate` be dedicated. Otherwise, unexpected side-effects may be encountered. ===== ==== Configuring with Java Configuration -The following configuration provides an example of configuring the outbound gateway using Java configuration: +The following configuration shows an example of how to configure the outbound gateway with Java configuration: + +==== [source, java] ---- @Configuration @@ -1130,11 +1021,13 @@ public class AmqpAsyncConfig { } ---- +==== ==== Configuring with the Java DSL -The following Spring Boot application provides an example of configuring the outbound adapter using the Java DSL: +The following Spring Boot application shows an example of how to configure the outbound adapter with the Java DSL: +==== [source, java] ---- @SpringBootApplication @@ -1166,20 +1059,20 @@ public class AmqpAsyncApplication { } ---- +==== [[content-type-conversion-outbound]] === Outbound Message Conversion -Spring AMQP 1.4 introduced the `ContentTypeDelegatingMessageConverter` where the actual converter is selected based +Spring AMQP 1.4 introduced the `ContentTypeDelegatingMessageConverter`, where the actual converter is selected based on the incoming content type message property. -This could be used by inbound endpoints. +This can be used by inbound endpoints. -Spring Integration _version 4.3_ now allows the `ContentTypeDelegatingMessageConverter` to be used on outbound -endpoints as well - with the `contentType` header specifiying which converter will be used. +As of Spring Integration version 4.3, you can use the `ContentTypeDelegatingMessageConverter` on outbound endpoints as well, with the `contentType` header specifying which converter is used. -The following configures a `ContentTypeDelegatingMessageConverter` with the default converter being the -`SimpleMessageConverter` (which handles java serialization and plain text), together with a JSON converter: +The following example configures a `ContentTypeDelegatingMessageConverter`, with the default converter being the `SimpleMessageConverter` (which handles Java serialization and plain text), together with a JSON converter: +==== [source, xml] ---- ---- +==== -Sending a message to `ctRequestChannel` with the `contentType` header set to `application/json` will cause the -JSON converter to be selected. +Sending a message to `ctRequestChannel` with the `contentType` header set to `application/json` causes the JSON converter to be selected. This applies to both the outbound channel adapter and gateway. [NOTE] ==== -Starting with _version 5.0_, headers that are added to the `MessageProperties` of the outbound message are never overwritten by mapped headers (by default). -Previously, this was only the case if the message converter was a `ContentTypeDelegatingMessageConverter` (in that case, the header was mapped first, so that the proper converter could be selected). +Starting with version 5.0, headers that are added to the `MessageProperties` of the outbound message are never overwritten by mapped headers (by default). +Previously, this was only the case if the message converter was a `ContentTypeDelegatingMessageConverter` (in that case, the header was mapped first so that the proper converter could be selected). For other converters, such as the `SimpleMessageConverter`, mapped headers overwrote any headers added by the converter. -This caused problems when an outbound message had some left over `contentType` header (perhaps from an inbound channel adapter) and the correct outbound `contentType` was incorrectly overwritten. +This caused problems when an outbound message had some leftover `contentType` headers (perhaps from an inbound channel adapter) and the correct outbound `contentType` was incorrectly overwritten. The work-around was to use a header filter to remove the header before sending the message to the outbound endpoint. -There are, however, cases where the previous behavior is desired. -For example, with a `String` payload containing JSON, the `SimpleMessageConverter` is not aware of the content and sets the `contentType` message property to `text/plain`, but your application would like to override that to `application/json` by setting the the `contentType` header of the message sent to the outbound endpoint. +There are, however, cases where the previous behavior is desired -- for example, when a `String` payload that contains JSON, the `SimpleMessageConverter` is not aware of the content and sets the `contentType` message property to `text/plain` but your application would like to override that to `application/json` by setting the `contentType` header of the message sent to the outbound endpoint. The `ObjectToJsonTransformer` does exactly that (by default). -There is now a property on the outbound channel adapter and gateway (as well as AMQP-backed channels) `headersMappedLast`. -Setting this to `true` will restore the behavior of overwriting the property added by the converter. +There is now a property called `headersMappedLast` on the outbound channel adapter and gateway (as well as on AMQP-backed channels). +Setting this to `true` restores the behavior of overwriting the property added by the converter. ==== [[amqp-user-id]] -=== Outbound User Id +=== Outbound User ID -Spring AMQP _version 1.6_ introduced a mechanism to allow the specification of a default user id for outbound messages. -It has always been possible to set the `AmqpHeaders.USER_ID` header which will now take precedence over the default. -This might be useful to message recipients; for inbound messages, if the message publisher sets the property, it is made available in the `AmqpHeaders.RECEIVED_USER_ID` header. -Note that RabbitMQ https://www.rabbitmq.com/validated-user-id.html[validates that the user id is the actual user id for the connection or one for which impersonation is allowed]. +Spring AMQP version 1.6 introduced a mechanism to allow the specification of a default user ID for outbound messages. +It has always been possible to set the `AmqpHeaders.USER_ID` header, which now takes precedence over the default. +This might be useful to message recipients. +For inbound messages, if the message publisher sets the property, it is made available in the `AmqpHeaders.RECEIVED_USER_ID` header. +Note that RabbitMQ https://www.rabbitmq.com/validated-user-id.html[validates that the user ID is the actual user ID for the connection or that the connection allows impersonation]. -To configure a default user id for outbound messages, configure it on a `RabbitTemplate` and configure the outbound adapter or gateway to use that template. -Similarly, to set the user id property on replies, inject an appropriately configured template into the inbound gateway. +To configure a default user ID for outbound messages, configure it on a `RabbitTemplate` and configure the outbound adapter or gateway to use that template. +Similarly, to set the user ID property on replies, inject an appropriately configured template into the inbound gateway. See the http://docs.spring.io/spring-amqp/reference/html/_reference.html#template-user-id[Spring AMQP documentation] for more information. [[amqp-delay]] @@ -1242,82 +1135,84 @@ See the http://docs.spring.io/spring-amqp/reference/html/_reference.html#templat Spring AMQP supports the http://docs.spring.io/spring-amqp/reference/html/_reference.html#delayed-message-exchange[RabbitMQ Delayed Message Exchange Plugin]. For inbound messages, the `x-delay` header is mapped to the `AmqpHeaders.RECEIVED_DELAY` header. -Setting the `AMQPHeaders.DELAY` header will cause the corresponding `x-delay` header to be set in outbound messages. +Setting the `AMQPHeaders.DELAY` header causes the corresponding `x-delay` header to be set in outbound messages. You can also specify the `delay` and `delayExpression` properties on outbound endpoints (`delay-expression` when using XML configuration). -This takes precedence over the `AmqpHeaders.DELAY` header. +These properties take precedence over the `AmqpHeaders.DELAY` header. [[amqp-channels]] -=== AMQP Backed Message Channels +=== AMQP-backed Message Channels -There are two Message Channel implementations available. -One is point-to-point, and the other is publish/subscribe. -Both of these channels provide a wide range of configuration attributes for the underlying AmqpTemplate and -SimpleMessageListenerContainer as you have seen on the Channel Adapters and Gateways. -However, the examples we'll show here are going to have minimal configuration. +There are two message channel implementations available. +One is point-to-point, and the other is publish-subscribe. +Both of these channels provide a wide range of configuration attributes for the underlying `AmqpTemplate` and +`SimpleMessageListenerContainer` (as shown earlier in this chapter for the channel adapters and gateways). +However, the examples we show here have minimal configuration. Explore the XML schema to view the available attributes. -A point-to-point channel would look like this: +A point-to-point channel might look like the following example: + +==== [source,xml] ---- ---- +==== -Under the covers a Queue named "si.p2pChannel" would be declared, and this channel will send to that Queue (technically by sending to the no-name Direct Exchange with a routing key that matches this Queue's name). -This channel will also register a consumer on that Queue. -If you want the channel to be "pollable" instead of message-driven, then simply provide the "message-driven" flag with -a value of `false`: +Under the covers, the preceding example causes a `Queue` named `si.p2pChannel` to be declared, and this channel sends to that `Queue` (technically, by sending to the no-name direct exchange with a routing key that matches the name of this `Queue`). +This channel also registers a consumer on that `Queue`. +If you want the channel to be "`pollable`" instead of message-driven, provide the `message-driven` flag with a value of `false`, as the following example shows: +==== [source,xml] ---- ---- +==== -A publish/subscribe channel would look like this: +A publish-subscribe channel might look like the following: + +==== [source,xml] ---- ---- +==== -Under the covers a Fanout Exchange named "si.fanout.pubSubChannel" would be declared, and this channel will send to that -Fanout Exchange. -This channel will also declare a server-named exclusive, auto-delete, non-durable Queue and bind that to the Fanout -Exchange while registering a consumer on that Queue to receive Messages. -There is no "pollable" option for a publish-subscribe-channel; it must be message-driven. +Under the covers, the preceding example causes a fanout exchange named `si.fanout.pubSubChannel` to be declared, and this channel sends to that fanout exchange. +This channel also declares a server-named exclusive, auto-delete, non-durable `Queue` and binds that to the fanout exchange while registering a consumer on that `Queue` to receive messages. +There is no "`pollable`" option for a publish-subscribe-channel. +It must be message-driven. -Starting with _version 4.1_ AMQP Backed Message Channels, alongside with `channel-transacted`, support +Starting with version 4.1, AMQP-backed message channels (in conjunction with `channel-transacted`) support `template-channel-transacted` to separate `transactional` configuration for the `AbstractMessageListenerContainer` and for the `RabbitTemplate`. -Note, previously, the `channel-transacted` was `true` by default, now it changed to `false` as standard default value -for the `AbstractMessageListenerContainer`. +Note that, previously, `channel-transacted` was `true` by default. +Now, by default, it is `false` for the `AbstractMessageListenerContainer`. -Prior to _version 4.3_, AMQP-backed channels only supported messages with `Serializable` payloads and headers. +Prior to version 4.3, AMQP-backed channels only supported messages with `Serializable` payloads and headers. The entire message was converted (serialized) and sent to RabbitMQ. -Now, you can set the `extract-payload` attribute (or `setExtractPayload()` when using Java configuration) to true. -When this flag is `true`, the message payload is converted and the headers mapped, in a similar manner to when using -channel adapters. -This allows AMQP-backed channels to be used with non-serializable payloads (perhaps with another message converter -such as the `Jackson2JsonMessageConverter`). -The default mapped headers are discussed in <>. -You can modify the mapping by providing custom mappers using the `outbound-header-mapper` and `inbound-header-mapper` -attributes. -You can now also specify a `default-delivery-mode`, used to set the delivery mode when there is no -`amqp_deliveryMode` header. +Now, you can set the `extract-payload` attribute (or `setExtractPayload()` when using Java configuration) to `true`. +When this flag is `true`, the message payload is converted and the headers are mapped, in a manner similar to when you use channel adapters. +This arrangement lets AMQP-backed channels be used with non-serializable payloads (perhaps with another message converter, such as the `Jackson2JsonMessageConverter`). +See "`<>`" for more about the default mapped headers. +You can modify the mapping by providing custom mappers that use the `outbound-header-mapper` and `inbound-header-mapper` attributes. +You can now also specify a `default-delivery-mode`, which is used to set the delivery mode when there is no `amqp_deliveryMode` header. By default, Spring AMQP `MessageProperties` uses `PERSISTENT` delivery mode. -IMPORTANT: Just as with other persistence-backed channels, AMQP-backed channels are intended to provide message -persistence to avoid message loss. -They are not intended to distribute work to other peer applications; for that purpose, use channel adapters instead. - -IMPORTANT: Starting with _version 5.0_, the pollable channel now blocks the poller thread for the specified `receiveTimeout` (default 1 second). -Previously, unlike other `PollableChannel` s, the thread returned immediately to the scheduler if no message was available, regardless of the receive timeout. -Blocking is a little more expensive than just using a `basicGet()` to retrieve a message (with no timeout) because a consumer has to be created to receive each message. -To restore the previous behavior, set the poller `receiveTimeout` to 0. +IMPORTANT: As with other persistence-backed channels, AMQP-backed channels are intended to provide message persistence to avoid message loss. +They are not intended to distribute work to other peer applications. +For that purpose, use channel adapters instead. +IMPORTANT: Starting with version 5.0, the pollable channel now blocks the poller thread for the specified `receiveTimeout` (the default is 1 second). +Previously, unlike other `PollableChannel` implementations, the thread returned immediately to the scheduler if no message was available, regardless of the receive timeout. +Blocking is a little more expensive than using a `basicGet()` to retrieve a message (with no timeout), because a consumer has to be created to receive each message. +To restore the previous behavior, set the poller's `receiveTimeout` to 0. ==== Configuring with Java Configuration -The following provides an example of configuring the channels using Java configuration: +The following example shows how to configure the channels with Java configuration: +==== [source, java] ---- @Bean @@ -1347,11 +1242,13 @@ public AmqpChannelFactoryBean pubSub(ConnectionFactory connectionFactory) { return factoryBean; } ---- +==== ==== Configuring with the Java DSL -The following provides an example of configuring the channels using the Java DSL: +The following example shows how to configure the channels with the Java DSL: +==== [source, java] ---- @Bean @@ -1384,127 +1281,88 @@ public IntegrationFlow pubSubInFlow(ConnectionFactory connectionFactory) { .get(); } ---- +==== [[amqp-message-headers]] === AMQP Message Headers ==== Overview -The Spring Integration AMQP Adapters will map all AMQP properties and headers automatically. -(This is a change in 4.3 - previously, only standard headers were mapped). -These properties will be copied by default to and from Spring Integration `MessageHeaders` using the -http://docs.spring.io/spring-integration/api/org/springframework/integration/amqp/support/DefaultAmqpHeaderMapper.html[DefaultAmqpHeaderMapper]. +The Spring Integration AMQP Adapters automatically map all AMQP properties and headers. +(This is a change from 4.3 - previously, only standard headers were mapped). +By default, these properties are copied to and from Spring Integration `MessageHeaders` by using the +http://docs.spring.io/spring-integration/api/org/springframework/integration/amqp/support/DefaultAmqpHeaderMapper.html[`DefaultAmqpHeaderMapper`]. -Of course, you can pass in your own implementation of AMQP specific header mappers, as the adapters have respective -properties to support that. +You can pass in your own implementation of AMQP-specific header mappers, as the adapters have properties to support doing so. -Any user-defined headers within the AMQP http://docs.spring.io/spring-amqp/api/org/springframework/amqp/core/MessageProperties.html[MessageProperties] WILL -be copied to or from an AMQP Message, unless explicitly negated by the _requestHeaderNames_ and/or -_replyHeaderNames_ properties of the `DefaultAmqpHeaderMapper`. -For an outbound mapper, no `x-*` headers are mapped by default; see the caution below for the reason why. +Any user-defined headers within the AMQP http://docs.spring.io/spring-amqp/api/org/springframework/amqp/core/MessageProperties.html[`MessageProperties`] are copied to or from an AMQP message, unless explicitly negated by the `requestHeaderNames` or `replyHeaderNames` properties of the `DefaultAmqpHeaderMapper`. +By default, for an outbound mapper, no `x-*` headers are mapped. +See the <> that appears later in this section for why. -To override the default, and revert to the pre-4.3 behavior, use `STANDARD_REQUEST_HEADERS` and +To override the default and revert to the pre-4.3 behavior, use `STANDARD_REQUEST_HEADERS` and `STANDARD_REPLY_HEADERS` in the properties. -TIP: When mapping user-defined headers, the values can also contain simple wildcard patterns (e.g. "foo*" or "*foo") -to be matched. +TIP: When mapping user-defined headers, the values can also contain simple wildcard patterns (such as 'thing*' or `*thing`) to be matched. `*` matches all headers. -Starting with _version 4.1_, the `AbstractHeaderMapper` (a `DefaultAmqpHeaderMapper` superclass) allows the -`NON_STANDARD_HEADERS` token to be configured for the _requestHeaderNames_ and/or _replyHeaderNames_ properties -(in addition to the existing `STANDARD_REQUEST_HEADERS` and `STANDARD_REPLY_HEADERS`) to map all user-defined headers. +Starting with version 4.1, the `AbstractHeaderMapper` (a `DefaultAmqpHeaderMapper` superclass) lets the `NON_STANDARD_HEADERS` token be configured for the `requestHeaderNames` and `replyHeaderNames` properties (in addition to the existing `STANDARD_REQUEST_HEADERS` and `STANDARD_REPLY_HEADERS`) to map all user-defined headers. -Class `org.springframework.amqp.support.AmqpHeaders` identifies the default headers that will be used by the +The `org.springframework.amqp.support.AmqpHeaders` class identifies the default headers that are used by the `DefaultAmqpHeaderMapper`: -* amqp_appId +* `amqp_appId` +* `amqp_clusterId` +* `amqp_contentEncoding` +* `amqp_contentLength` +* `content-type` (see "`<>`") +* `amqp_correlationId` +* `amqp_delay` +* `amqp_deliveryMode` +* `amqp_deliveryTag` +* `amqp_expiration` +* `amqp_messageCount` +* `amqp_messageId` +* `amqp_receivedDelay` +* `amqp_receivedDeliveryMode` +* `amqp_receivedExchange` +* `amqp_receivedRoutingKey` +* `amqp_redelivered` +* `amqp_replyTo` +* `amqp_timestamp` +* `amqp_type` +* `amqp_userId` +* `amqp_publishConfirm` +* `amqp_publishConfirmNackCause` +* `amqp_returnReplyCode` +* `amqp_returnReplyText` +* `amqp_returnExchange` +* `amqp_returnRoutingKey` +* `amqp_channel` +* `amqp_consumerTag` +* `amqp_consumerQueue` -* amqp_clusterId - -* amqp_contentEncoding - -* amqp_contentLength - -* content-type (see <>) - -* amqp_correlationId - -* amqp_delay - -* amqp_deliveryMode - -* amqp_deliveryTag - -* amqp_expiration - -* amqp_messageCount - -* amqp_messageId - -* amqp_receivedDelay - -* amqp_receivedDeliveryMode - -* amqp_receivedExchange - -* amqp_receivedRoutingKey - -* amqp_redelivered - -* amqp_replyTo - -* amqp_timestamp - -* amqp_type - -* amqp_userId - -* amqp_publishConfirm - -* amqp_publishConfirmNackCause - -* amqp_returnReplyCode - -* amqp_returnReplyText - -* amqp_returnExchange - -* 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. -For example, when you use https://www.rabbitmq.com/federated-exchanges.html[Federation], the received message may have -a property named `x-received-from` which contains the node that sent the message. -If you use the wildcard character `*` for the request and reply header mapping on the Inbound Gateway, this header will -be copied as well, -which may cause some issues with federation; this reply message may be federated back to the -sending broker, which will think that a message is looping and is thus silently dropped. -If you wish to use the convenience of wildcard header mapping, you may need to filter out some headers in the -downstream flow. -For example, to avoid copying the `x-received-from` header back to the reply you can use -`` -before sending the reply to the AMQP Inbound Gateway. -Alternatively, you could explicitly list those properties that you actually want mapped instead of using -wildcards. -For these reasons, for inbound messages, the mapper by default does not map any `x-*` headers; it also does not map -the `deliveryMode` to `amqp_deliveryMode` header, to avoid propagation of that header from an inbound message to an -outbound message. +CAUTION: As mentioned earlier in this section, using a header mapping pattern of`*` is a common way to copy all headers. +However, this can have some unexpected side effects, because certain RabbitMQ proprietary properties/headers are also +copied. +For example, when you use https://www.rabbitmq.com/federated-exchanges.html[federation], the received message may have +a property named `x-received-from`, which contains the node that sent the message. +If you use the wildcard character `*` for the request and reply header mapping on the inbound gateway, this header is copied, which may cause some issues with federation. +This reply message may be federated back to the sending broker, which may think that a message is looping and, as a result, silently drop it. +If you wish to use the convenience of wildcard header mapping, you may need to filter out some headers in the downstream flow. +For example, to avoid copying the `x-received-from` header back to the reply you can use `` before sending the reply to the AMQP inbound gateway. +Alternatively, you can explicitly list those properties that you actually want mapped, instead of using wildcards. +For these reasons, for inbound messages, the mapper (by default) does not map any `x-*` headers. +It also does not map the `deliveryMode` to the `amqp_deliveryMode` header, to avoid propagation of that header from an inbound message to an outbound message. Instead, this header is mapped to `amqp_receivedDeliveryMode`, which is not mapped on output. -Starting with _version 4.3_, patterns in the header mappings can be negated by preceding the pattern with `!`. +Starting with version 4.3, patterns in the header mappings can be negated by preceding the pattern with `!`. Negated patterns get priority, so a list such as -`STANDARD_REQUEST_HEADERS,foo,ba*,!bar,!baz,qux,!foo` will *NOT* map `foo` -(nor `bar` nor `baz`); the standard headers plus `bad`, `qux` will be mapped. +`STANDARD_REQUEST_HEADERS,thing1,ba*,!thing2,!thing3,qux,!thing1` does not map `thing1` +(nor `thing2` nor `thing3`). +The standard headers plus `bad` and `qux` are mapped. -IMPORTANT: If you have a user defined header that begins with `!` that you *do* wish to map, you need to escape it with -`\` thus: `STANDARD_REQUEST_HEADERS,\!myBangHeader` and it *WILL* be mapped. +IMPORTANT: If you have a user-defined header that begins with `!` that you do wish to map, you need to escape it with +`\`, as follows: `STANDARD_REQUEST_HEADERS,\!myBangHeader`. The header named `!myBangHeader` is now mapped. NOTE: Starting with _version 5.1_, the `DefaultAmqpHeaderMapper` will fall back to mapping `MessageHeaders.ID` and `MessageHeaders.TIMESTAMP` to `MessageProperties.messageId` and `MessageProperties.timestamp` respectively, if the corresponding `amqp_messageId` or `amqp_timestamp` headers are not present on outbound messages. Inbound properties will be mapped to the `amqp_*` headers as before. @@ -1526,17 +1384,20 @@ Inbound mapping ignored the headers map value. [[amqp-strict-ordering]] === Strict Message Ordering +This section describes message ordering for inbound and outbound messages. + ==== Inbound If you require strict ordering of inbound messages, you must configure the inbound listener container's `prefetchCount` property to `1`. -This is because if a message fails and is redelivered, it will arrive after existing prefetched messages. -Since Spring AMQP _version 2.0_, the `prefetchCount` defaults to `250` for improved performance. +This is because, if a message fails and is redelivered, it arrives after existing prefetched messages. +Since Spring AMQP version 2.0, the `prefetchCount` defaults to `250` for improved performance. Strict ordering requirements come at the cost of decreased performance. ==== Outbound -Consider the following simple integration flow: +Consider the following integration flow: +==== [source, java] ---- @Bean @@ -1548,14 +1409,19 @@ public IntegrationFlow flow(RabbitTemplate template) { .get(); } ---- +==== -Let's say we send a message `a,b,c` to the gateway, while it is likely that messages `A`, `B`, `C` will be sent in order, there is no guarantee. -This is because the template "borrows" a channel from the cache for each send and there is no guarantee that the same channel will be used for each. -One solution is to start a transaction before the splitter, but transactions are very expensive in RabbitMQ and can reduce performance several hundred fold. +Suppose we send messages `A`, `B` and `C` to the gateway. +While it is likely that messages `A`, `B`, `C` are sent in order, there is no guarantee. +This is because the template "`borrows`" a channel from the cache for each send operation, and there is no guarantee that the same channel is used for each message. +One solution is to start a transaction before the splitter, but transactions are expensive in RabbitMQ and can reduce performance several hundred fold. -To solve this problem in a more efficient manner, starting with _version 5.1_, Spring Integration provides the `BoundRabbitChannelAdvice` which is a `HandleMessageAdvice` - see <>. -When applied before the splitter, this ensures that all downstream operations are performed on the same channel and, optionally, can wait until publisher confirms for all sent messages are received (if the connection factory is configured for confirms). +To solve this problem in a more efficient manner, starting with version 5.1, Spring Integration provides the `BoundRabbitChannelAdvice` which is a `HandleMessageAdvice`. +See "`<>`". +When applied before the splitter, it ensures that all downstream operations are performed on the same channel and, optionally, can wait until publisher confirmations for all sent messages are received (if the connection factory is configured for confirmations). +The following example shows how to use `BoundRabbitChannelAdvice`: +==== [source, java] ---- @Bean @@ -1568,33 +1434,29 @@ public IntegrationFlow flow(RabbitTemplate template) { .get(); } ---- +==== Notice that the same `RabbitTemplate` (which implements `RabbitOperations`) is used in the advice and the outbound adapter. The advice runs the downstream flow within the template's `invoke` method so that all operations run on the same channel. -If the optional timeout is provided, when the flow completes, the advice calls the `waitForConfirmsOrDie` method, which will throw an exception if the confirms are not received within the specified time. +If the optional timeout is provided, when the flow completes, the advice calls the `waitForConfirmsOrDie` method, which throws an exception if the confirmations are not received within the specified time. -IMPORTANT: There must be no thread handoffs in the downstream flow (`QueueChannel`, `ExecutorChannel`, etc). +IMPORTANT: There must be no thread handoffs in the downstream flow (`QueueChannel`, `ExecutorChannel`, and others). === AMQP Samples -To experiment with the AMQP adapters, check out the samples available in the Spring Integration Samples Git repository at: +To experiment with the AMQP adapters, check out the samples available in the Spring Integration samples git repository at https://github.com/spring-projects/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] +Currently, one sample demonstrates the basic functionality of the Spring Integration AMQP adapter by using an outbound channel adapter and an inbound channel adapter. +As AMQP broker implementation in the sample uses http://www.rabbitmq.com/[RabbitMQ]. +NOTE: In order to run the example, you need a running instance of RabbitMQ. +A local installation with just the basic defaults suffices. +For detailed RabbitMQ installation procedures, see http://www.rabbitmq.com/install.html[http://www.rabbitmq.com/install.html] +Once the sample application is started, enter some text on the command prompt and a message containing that entered text is dispatched to the AMQP queue. +In return, that message is retrieved by Spring Integration and printed to the console. -Currently there is one sample available that demonstrates the basic functionality of the Spring Integration AMQP Adapter using an Outbound Channel Adapter and an Inbound Channel Adapter. -As AMQP Broker implementation the sample uses RabbitMQ (http://www.rabbitmq.com/[http://www.rabbitmq.com/]). - -NOTE: In order to run the example you will need a running instance of RabbitMQ. -A local installation with just the basic defaults will be sufficient. -For detailed RabbitMQ installation procedures please visit: http://www.rabbitmq.com/install.html[http://www.rabbitmq.com/install.html] - -Once the sample application is started, you enter some text on the command prompt and a message containing that entered text is dispatched to the AMQP queue. -In return that message is retrieved via Spring Integration and then printed to the console. - -The image belows illustrates the basic set of Spring Integration components used in this sample. +The following image illustrates the basic set of Spring Integration components used in this sample. .The Spring Integration graph of the AMQP sample - image::images/spring-integration-amqp-sample-graph.png[] diff --git a/src/reference/asciidoc/barrier.adoc b/src/reference/asciidoc/barrier.adoc index 13736a903b..88e9e2c98c 100644 --- a/src/reference/asciidoc/barrier.adoc +++ b/src/reference/asciidoc/barrier.adoc @@ -6,9 +6,10 @@ For example, consider an HTTP request that publishes a message to RabbitMQ. We might wish to not reply to the user until the RabbitMQ broker has issued an acknowledgment that the message was received. -Spring Integration _version 4.2_ introduced the `` component for this purpose. -The underlying `MessageHandler` is the `BarrierMessageHandler`; this class also implements -`MessageTriggerAction` where a message passed to the `trigger()` method releases a corresponding thread in the +In version 4.2, Spring Integration introduced the `` component for this purpose. +The underlying `MessageHandler` is the `BarrierMessageHandler`. +This class also implements +`MessageTriggerAction`, in which a message passed to the `trigger()` method releases a corresponding thread in the `handleRequestMessage()` method (if present). The suspended thread and trigger thread are correlated by invoking a `CorrelationStrategy` on the messages. @@ -16,29 +17,27 @@ When a message is sent to the `input-channel`, the thread is suspended for up to a corresponding trigger message. The default correlation strategy uses the `IntegrationMessageHeaderAccessor.CORRELATION_ID` header. When a trigger message arrives with the same correlation, the thread is released. -The message sent to the `output-channel` after release is constructed using a `MessageGroupProcessor`. -By default, the message is a `Collection` of the two payloads and the headers are merged, using a +The message sent to the `output-channel` after release is constructed by using a `MessageGroupProcessor`. +By default, the message is a `Collection` of the two payloads, and the headers are merged by using a `DefaultAggregatingMessageGroupProcessor`. -CAUTION: If the `trigger()` method is invoked first (or after the main thread times out), it will be suspended -for up to `timeout` waiting for the suspending message to arrive. -If you do not want to suspend the trigger thread, consider handing off to a `TaskExecutor` instead so its thread -will be suspended instead. +CAUTION: If the `trigger()` method is invoked first (or after the main thread times out), it is suspended for up to `timeout` waiting for the suspending message to arrive. +If you do not want to suspend the trigger thread, consider handing off to a `TaskExecutor` instead so that its thread is suspended instead. -The `requires-reply` property determines the action if the suspended thread times out before the trigger message -arrives. -By default, it is `false` which means the endpoint simply returns `null`, the flow ends and the thread returns to the +The `requires-reply` property determines the action to take if the suspended thread times out before the trigger message arrives. +By default, it is `false`, which means the endpoint returns `null`, the flow ends, and the thread returns to the caller. When `true`, a `ReplyRequiredException` is thrown. -You can call the `trigger()` method programmatically (obtain the bean reference using the name `barrier.handler` - - where _barrier_ is the bean name of the barrier endpoint) or you can configure -an `` to trigger the release. +You can call the `trigger()` method programmatically (obtain the bean reference by using the name, `barrier.handler` -- where `barrier` is the bean name of the barrier endpoint). +Alternatively, you can configure an `` to trigger the release. -IMPORTANT: Only one thread can be suspended with the same correlation; the same correlation can be used multiple times -but only once concurrently. +IMPORTANT: Only one thread can be suspended with the same correlation. +The same correlation can be used multiple times but only once concurrently. An exception is thrown if a second thread arrives with the same correlation. +The following example shows how to use a custom header for correlation: + [source, xml] ---- ---- -In this example, a custom header is used for correlation. -Either the thread sending a message to `in` or the one sending a message to `release` will wait for -up to 10 seconds until the other arrives. -When the message is released, the `out` channel will be sent a message combining the result of invoking the -custom `MessageGroupProcessor` bean `myOutputProcessor`. -If the main thread times out and a trigger arrives later, you can configure a discard channel to which the late trigger will be sent. -Java configuration is shown below. +Depending on which one has a message arrive first, either the thread sending a message to `in` or the thread sending a message to `release` waits for up to ten seconds until the other message arrives. +When the message is released, the `out` channel is sent a message that combines the result of invoking the custom `MessageGroupProcessor` bean, named `myOutputProcessor`. +If the main thread times out and a trigger arrives later, you can configure a discard channel to which the late trigger is sent. +The following example shows the Java configuration to do so: [source, java] ---- @@ -90,6 +86,4 @@ public class Config { } ---- -See the -https://github.com/spring-projects/spring-integration-samples/tree/master/basic/barrier[barrier sample application] -for an example of this component. +For an example of this component, see the https://github.com/spring-projects/spring-integration-samples/tree/master/basic/barrier[barrier sample application]. diff --git a/src/reference/asciidoc/bridge.adoc b/src/reference/asciidoc/bridge.adoc index 3b78940338..e48e576aed 100644 --- a/src/reference/asciidoc/bridge.adoc +++ b/src/reference/asciidoc/bridge.adoc @@ -1,41 +1,48 @@ [[bridge]] === Messaging Bridge -[[bridge-introduction]] -==== Introduction - -A Messaging Bridge is a relatively trivial endpoint that simply connects two Message Channels or Channel Adapters. +A messaging bridge is a relatively trivial endpoint that connects two message channels or channel adapters. For example, you may want to connect a `PollableChannel` to a `SubscribableChannel` so that the subscribing endpoints do not have to worry about any polling configuration. -Instead, the Messaging Bridge provides the polling configuration. +Instead, the messaging bridge provides the polling configuration. -By providing an intermediary poller between two channels, a Messaging Bridge can be used to throttle inbound Messages. -The poller's trigger will determine the rate at which messages arrive on the second channel, and the poller's "maxMessagesPerPoll" property will enforce a limit on the throughput. +By providing an intermediary poller between two channels, you can use a messaging bridge to throttle inbound messages. +The poller's trigger determines the rate at which messages arrive on the second channel, and the poller's `maxMessagesPerPoll` property enforces a limit on the throughput. -Another valid use for a Messaging Bridge is to connect two different systems. -In such a scenario, Spring Integration's role would be limited to making the connection between these systems and managing a poller if necessary. -It is probably more common to have at least a _Transformer_ between the two systems to translate between their formats, and in that case, the channels would be provided as the 'input-channel' and 'output-channel' of a Transformer endpoint. -If data format translation is not required, the Messaging Bridge may indeed be sufficient. +Another valid use for a messaging bridge is to connect two different systems. +In such a scenario, Spring Integration's role is limited to making the connection between these systems and managing a poller, if necessary. +It is probably more common to have at least a transformer between the two systems, to translate between their formats. +In that case, the channels can be provided as the 'input-channel' and 'output-channel' of a transformer endpoint. +If data format translation is not required, the messaging bridge may indeed be sufficient. [[bridge-namespace]] ==== Configuring a Bridge with XML -The element is used to create a Messaging Bridge between two Message Channels or Channel Adapters. -Simply provide the "input-channel" and "output-channel" attributes: +You can use the `` element is used to create a messaging bridge between two message channels or channel adapters. +To do so, provide the `input-channel` and `output-channel` attributes, as the following example shows: + +==== [source,xml] ---- ---- +==== -As mentioned above, a common use case for the Messaging Bridge is to connect a `PollableChannel` to a `SubscribableChannel`, and when performing this role, the Messaging Bridge may also serve as a throttler: +As mentioned above, a common use case for the messaging bridge is to connect a `PollableChannel` to a `SubscribableChannel`. +When performing this role, the messaging bridge may also serve as a throttler: + +==== [source,xml] ---- ---- +==== -Connecting Channel Adapters is just as easy. -Here is a simple echo example between the "stdin" and "stdout" adapters from Spring Integration's "stream" namespace. +You can use a similar mechanism to connecting channel adapters. +The following example shows a simple "`echo`" between the `stdin` and `stdout` adapters from Spring Integration's `stream` namespace: + +==== [source,xml] ---- @@ -44,16 +51,20 @@ Here is a simple echo example between the "stdin" and "stdout" adapters from Spr ---- +==== -Of course, the configuration would be similar for other (potentially more useful) Channel Adapter bridges, such as File to JMS, or Mail to File. -The various Channel Adapters will be discussed in upcoming chapters. +Similar configurations work for other (potentially more useful) Channel Adapter bridges, such as file-to-JMS or mail-to-file. +Upcoming chapters cover the various channel adapters. -NOTE: If no 'output-channel' is defined on a bridge, the reply channel provided by the inbound Message will be used, if available. -If neither output or reply channel is available, an Exception will be thrown. +NOTE: If no 'output-channel' is defined on a bridge, the reply channel provided by the inbound message is used, if available. +If neither an output nor a reply channel is available, an exception is thrown. [[bridge-annot]] ==== Configuring a Bridge with Java Configuration +The following example shows how to configure a bridge in Java by using the `@BridgeFrom` annotation: + +==== [source, java] ---- @Bean @@ -67,8 +78,9 @@ public SubscribableChannel direct() { return new DirectChannel(); } ---- +==== -or +The following example shows how to configure a bridge in Java by using the `@BridgeTo` annotation: [source, java] ---- @@ -84,7 +96,7 @@ public SubscribableChannel direct() { } ---- -Or, using a `BridgeHandler`: +Alternately, you can use a `BridgeHandler`, as the following example shows: [source, java] ---- @@ -101,6 +113,8 @@ public BridgeHandler bridge() { [[bridge-dsl]] ==== Configuring a Bridge with the Java DSL +You can use the Java Domain Specific Language (DSL) to configure a bridge, as the following example shows: + [source, java] ---- @Bean diff --git a/src/reference/asciidoc/chain.adoc b/src/reference/asciidoc/chain.adoc index 8f804f2f67..42c3a7a956 100644 --- a/src/reference/asciidoc/chain.adoc +++ b/src/reference/asciidoc/chain.adoc @@ -1,126 +1,137 @@ [[chain]] === Message Handler Chain -[[chain-introduction]] -==== Introduction +The `MessageHandlerChain` is an implementation of `MessageHandler` that can be configured as a single message endpoint while actually delegating to a chain of other handlers, such as filters, transformers, splitters, and so on. +When several handlers need to be connected in a fixed, linear progression, this can lead to a much simpler configuration. +For example, it is fairly common to provide a transformer before other components. +Similarly, when you provide a filter before some other component in a chain, you essentially create a http://www.eaipatterns.com/MessageSelector.html[selective consumer]. +In either case, the chain requires only a single `input-channel` and a single `output-channel`, eliminating the need to define channels for each individual component. -The `MessageHandlerChain` is an implementation of `MessageHandler` that can be configured as a single Message Endpoint while actually delegating to a chain of other handlers, such as Filters, Transformers, Splitters, and so on. -This can lead to a much simpler configuration when several handlers need to be connected in a fixed, linear progression. -For example, it is fairly common to provide a Transformer before other components. -Similarly, when providing a _Filter_ before some other component in a chain, you are essentially creating a http://www.eaipatterns.com/MessageSelector.html[Selective Consumer]. -In either case, the chain only requires a single `input-channel` and a single `output-channel` eliminating the need to define channels for each individual component. - -TIP: Spring Integration's `Filter` provides a boolean property `throwExceptionOnRejection`. -When providing multiple Selective Consumers on the same point-to-point channel with different acceptance criteria, this value should be set to 'true' (the default is false) so that the dispatcher will know that the Message was rejected and as a result will attempt to pass the Message on to other subscribers. -If the Exception were not thrown, then it would appear to the dispatcher as if the Message had been passed on successfully even though the Filter had _dropped_ the Message to prevent further processing. -If you do indeed want to "drop" the Messages, then the Filter's 'discard-channel' might be useful since it does give you a chance to perform some operation with the dropped message (e.g. -send to a JMS queue or simply write to a log). +TIP: Spring Integration's `Filter` provides a boolean property: `throwExceptionOnRejection`. +When you provide multiple selective consumers on the same point-to-point channel with different acceptance criteria, you should set this value 'true' (the default is `false`) so that the dispatcher knows that the message was rejected and, as a result, tries to pass the message on to other subscribers. +If the exception were not thrown, it would appear to the dispatcher that the message had been passed on successfully even though the filter had dropped the message to prevent further processing. +If you do indeed want to "`drop`" the messages, the filter's 'discard-channel' might be useful, since it does give you a chance to perform some operation with the dropped message (such as sending it to a JMS queue or writing it to a log). The handler chain simplifies configuration while internally maintaining the same degree of loose coupling between components, and it is trivial to modify the configuration if at some point a non-linear arrangement is required. -Internally, the chain will be expanded into a linear setup of the listed endpoints, separated by anonymous channels. -The reply channel header will not be taken into account within the chain: only after the last handler is invoked will the resulting message be forwarded on to the reply channel or the chain's output channel. -Because of this setup all handlers except the last required to implement the MessageProducer interface (which provides a 'setOutputChannel()' method). -The last handler only needs an output channel if the outputChannel on the MessageHandlerChain is set. +Internally, the chain is expanded into a linear setup of the listed endpoints, separated by anonymous channels. +The reply channel header is not taken into account within the chain. +Only after the last handler is invoked is the resulting message forwarded to the reply channel or the chain's output channel. +Because of this setup, all handlers except the last must implement the `MessageProducer` interface (which provides a 'setOutputChannel()' method). +If the `outputChannel` on the `MessageHandlerChain` is set, the last handler needs only an output channel. NOTE: As with other endpoints, the `output-channel` is optional. -If there is a reply Message at the end of the chain, the output-channel takes precedence, but if not available, the chain handler will check for a reply channel header on the inbound Message as a fallback. +If there is a reply message at the end of the chain, the output-channel takes precedence. +However, if it is not available, the chain handler checks for a reply channel header on the inbound message as a fallback. -In most cases there is no need to implement MessageHandlers yourself. -The next section will focus on namespace support for the chain element. -Most Spring Integration endpoints, like Service Activators and Transformers, are suitable for use within a `MessageHandlerChain`. +In most cases, you need not implement `MessageHandler` yourself. +The next section focuses on namespace support for the chain element. +Most Spring Integration endpoints, such as service activators and transformers, are suitable for use within a `MessageHandlerChain`. [[chain-namespace]] ==== Configuring a Chain -The element provides an `input-channel` attribute, and if the last element in the chain is capable of producing reply messages (optional), it also supports an `output-channel` attribute. +The `` element provides an `input-channel` attribute. +If the last element in the chain is capable of producing reply messages (optional), it also supports an `output-channel` attribute. The sub-elements are then filters, transformers, splitters, and service-activators. -The last element may also be a router or an outbound-channel-adapter. +The last element may also be a router or an outbound channel adapter. +The following example shows a chain definition: + +==== [source,xml] ---- - + ---- +==== -The element used in the above example will set a message header named "foo" with a value of "bar" on the message. +The `` element used in the preceding example sets a message header named `thing1` with a value of `thing2` on the message. A header enricher is a specialization of `Transformer` that touches only header values. -You could obtain the same result by implementing a MessageHandler that did the header modifications and wiring that as a bean, but the header-enricher is obviously a simpler option. +You could obtain the same result by implementing a `MessageHandler` that did the header modifications and wiring that as a bean, but the header-enricher is a simpler option. -The can be configured as the last 'black-box' consumer of the message flow. -For this solution it is enough to put at the end of the some : +The `` can be configured as the last 'black-box' consumer of the message flow. +For this solution, you can to put it at the end of the some , as the following example shows: + +==== [source,xml] ---- - + ---- +==== -_Disallowed Attributes and Elements_ - -It is important to note that certain attributes, such as *order* and *input-channel* are not allowed to be specified on components used within a _chain_. -The same is true for the *poller* sub-element. - +.Disallowed Attributes and Elements [IMPORTANT] ===== -For the _Spring Integration_ core components, the XML Schema itself will enforce some of these constraints. -However, for non-core components or your own custom components, these constraints are enforced by the XML namespace parser, not by the XML Schema. +Certain attributes, such as `order` and `input-channel` are not allowed to be specified on components used within a chain. +The same is true for the poller sub-element. -These XML namespace parser constraints were added with _Spring Integration 2.2_. -The XML namespace parser will throw an `BeanDefinitionParsingException` if you try to use disallowed attributes and elements. +For the Spring Integration core components, the XML schema itself enforces some of these constraints. +However, for non-core components or your own custom components, these constraints are enforced by the XML namespace parser, not by the XML schema. + +These XML namespace parser constraints were added with Spring Integration 2.2. +If you try to use disallowed attributes and elements, the XML namespace parser throws a `BeanDefinitionParsingException`. ===== -_'id' Attribute_ +==== Using the 'id' Attribute -Beginning with Spring Integration 3.0, if a chain element is given an _id_, the bean name for the element is a combination of the chain's _id_ and the _id_ of the element itself. -Elements without an _id_ are not registered as beans, but they are given `componentName` s that include the chain id. -For example: +Beginning with Spring Integration 3.0, if a chain element is given an `id` attribute, the bean name for the element is a combination of the chain's `id` and the `id` of the element itself. +Elements without `id` attributes are not registered as beans, but each one is given a `componentName` that includes the chain `id`. +Consider the following example: + +==== [source,xml] ---- - - + + ---- +==== +In the preceding example: +* The `` root element has an `id` of 'somethingChain'. +Consequently, the `AbstractEndpoint` implementation (`PollingConsumer` or `EventDrivenConsumer`, depending on the `input-channel` type) bean takes this value as its bean name. -* The `` root element has an _id_ 'fooChain'. -So, the `AbstractEndpoint` implementation (`PollingConsumer` or `EventDrivenConsumer`, depending on the _input-channel_ type) bean takes this value as it's bean name. +* The `MessageHandlerChain` bean acquires a bean alias ('somethingChain.handler'), which allows direct access to this bean from the `BeanFactory`. -* The `MessageHandlerChain` bean acquires a bean alias 'fooChain.handler', which allows direct access to this bean from the `BeanFactory`. +* The `` is not a fully fledged messaging endpoint (it is not a `PollingConsumer` or `EventDrivenConsumer`). +It is a `MessageHandler` within the ``. +In this case, the bean name registered with the `BeanFactory` is 'somethingChain$child.somethingService.handler'. -* The `` is not a fully-fledged Messaging Endpoint (`PollingConsumer` or `EventDrivenConsumer`) - it is simply a `MessageHandler` within the ``. -In this case, the bean name registered with the `BeanFactory` is 'fooChain$child.fooService.handler'. +* The `componentName` of this `ServiceActivatingHandler` takes the same value but without the '.handler' suffix. +It becomes 'somethingChain$child.somethingService'. -* The _componentName_ of this `ServiceActivatingHandler` takes the same value, but without the '.handler' suffix - 'fooChain$child.fooService'. - -* The last `` sub-component, ``, doesn't have an _id_ attribute. -Its _componentName_ is based on its position in the ``. -In this case, it is 'fooChain$child#1'. +* The last `` sub-component, ``, does not have an `id` attribute. +Its `componentName` is based on its position in the ``. +In this case, it is 'somethingChain$child#1'. (The final element of the name is the order within the chain, beginning with '#0'). -Note, this transformer isn't registered as a bean within the application context, so, it doesn't get a _beanName_, however its _componentName_ has a value which is useful for logging etc. +Note, this transformer is not registered as a bean within the application context, so it does not get a `beanName`. +However its `componentName` has a value that is useful for logging and other purposes. -The _id_ attribute for `` elements allows them to be eligible for <> and they are trackable via <>. -They can also be accessed from the `BeanFactory` using the appropriate bean name as discussed above. +The `id` attribute for `` elements lets them be eligible for <>, and they are trackable in the <>. +You can access them from the `BeanFactory` by using the appropriate bean name, as discussed earlier. -TIP: It is useful to provide an explicit _id_ attribute on `` s to simplify the identification of sub-components in logs, and to provide access to them from the `BeanFactory` etc. +TIP: It is useful to provide an explicit `id` attribute on `` elements to simplify the identification of sub-components in logs and to provide access to them from the `BeanFactory` etc. -_Calling a Chain from within a Chain_ +==== Calling a Chain from within a Chain -Sometimes you need to make a nested call to another chain from within a chain and then come back and continue execution within the original chain. -To accomplish this you can utilize a Messaging Gateway by including a element. -For example: +Sometimes, you need to make a nested call to another chain from within a chain and then come back and continue execution within the original chain. +To accomplish this, you can use a messaging gateway by including a element, as the following example shows: +==== [source,xml] ---- @@ -152,10 +163,12 @@ For example: ---- +==== -In the above example the _nested-chain-a_ will be called at the end of _main-chain_ processing by the 'gateway' element configured there. -While in _nested-chain-a_ a call to a _nested-chain-b_ will be made after header enrichment and then it will come back to finish execution in _nested-chain-b_. -Finally the flow returns to the _main-chain_. -When the nested version of a element is defined in the chain, it does not require the `service-interface` attribute. -Instead, it simple takes the message in its current state and places it on the channel defined via the `request-channel` attribute. -When the downstream flow initiated by that gateway completes, a `Message` will be returned to the gateway and continue its journey within the current chain. +In the preceding example, `nested-chain-a` is called at the end of `main-chain` processing by the 'gateway' element configured there. +While in `nested-chain-a`, a call to a `nested-chain-b` is made after header enrichment. +Then the flow comes back to finish execution in `nested-chain-b`. +Finally, the flow returns to `main-chain`. +When the nested version of a `` element is defined in the chain, it does not require the `service-interface` attribute. +Instead, it takes the message in its current state and places it on the channel defined in the `request-channel` attribute. +When the downstream flow initiated by that gateway completes, a `Message` is returned to the gateway and continues its journey within the current chain. diff --git a/src/reference/asciidoc/changes-1.0-2.0.adoc b/src/reference/asciidoc/changes-1.0-2.0.adoc index 4f54293ec6..ffbcc14447 100644 --- a/src/reference/asciidoc/changes-1.0-2.0.adoc +++ b/src/reference/asciidoc/changes-1.0-2.0.adoc @@ -1,9 +1,7 @@ [[migration-1.0-2.0]] -=== Changes between 1.0 and 2.0 +=== Changes between Versions 1.0 and 2.0 -For a detailed migration guide in regards to upgrading an existing application that uses Spring Integration older than version 2.0, please see: - -https://github.com/spring-projects/spring-integration/wiki/Spring-Integration-1.0-to-2.0-Migration-Guide[Spring Integration 1.0 to 2.0 Migration Guide] +See the https://github.com/spring-projects/spring-integration/wiki/Spring-Integration-1.0-to-2.0-Migration-Guide[Migration Guide] for important changes that might affect your applications. [[migration-spring-30-support]] ==== Spring 3 support @@ -13,166 +11,164 @@ Spring Integration 2.0 is built on top of Spring 3.0.5 and makes many of its fea [[spel-support]] ===== Support for the Spring Expression Language (SpEL) -You can now use SpEL expressions within the _transformer, router, filter, - splitter, aggregator, service-activator, header-enricher_, and many more elements of the Spring Integration core namespace as well as various adapters. -There are many samples provided throughout this manual. +You can now use SpEL expressions within the transformer, router, filter, splitter, aggregator, service-activator, header-enricher, and many more elements of the Spring Integration core namespace as well as within various adapters. +This guide includes many samples. [[conversion-support]] -===== ConversionService and Converter +===== Conversion Service and Converter -You can now benefit from _Conversion Service_ support provided with Spring while configuring many Spring Integration components such as http://www.eaipatterns.com/DatatypeChannel.html[Datatype Channel]. -See <> as well <>. -Also, the SpEL support mentioned in the previous point also relies upon the ConversionService. -Therefore, you can register Converters once, and take advantage of them anywhere you are using SpEL expressions. +You can now benefit from the conversion service support provided with Spring while configuring many Spring Integration components, such as a http://www.eaipatterns.com/DatatypeChannel.html[Datatype channel]. +See "`<>`" and "`<>`". +Also, the SpEL support mentioned in the previous point also relies upon the conversion service. +Therefore, you can register converters once and take advantage of them anywhere you use SpEL expressions. [[task-scheduler-poller-support]] -===== TaskScheduler and Trigger +===== `TaskScheduler` and `Trigger` -Spring 3.0 defines two new strategies related to scheduling: _TaskScheduler and Trigger_ Spring Integration (which uses a lot of scheduling) now builds upon these. -In fact, Spring Integration 1.0 had originally defined some of the components (e.g. -CronTrigger) that have now been migrated into Spring 3.0's core API. -Now, you can benefit from reusing the same components within the entire Application Context (not just Spring Integration configuration). -Configuration of Spring Integration Pollers has been greatly simplified as well by providing attributes for directly configuring rates, delays, cron expressions, and trigger references. -See <> for sample configurations. +Spring 3.0 defines two new strategies related to scheduling: `TaskScheduler` and `Trigger`. +Spring Integration (which uses a lot of scheduling) now builds upon these. +In fact, Spring Integration 1.0 had originally defined some of the components (such as `CronTrigger`) that have now been migrated into Spring 3.0's core API. +Now you can benefit from reusing the same components within the entire application context (not just Spring Integration configuration). +We also greatly simplified configuration of Spring Integration pollers by providing attributes for directly configuring rates, delays, cron expressions, and trigger references. +See "`<>`" for sample configurations. [[rest-support]] -===== RestTemplate and HttpMessageConverter +===== `RestTemplate` and `HttpMessageConverter` -Our outbound HTTP adapters now delegate to Spring's RestTemplate for executing the HTTP request and handling its response. -This also means that you can reuse any custom HttpMessageConverter implementations. -See <> for more details. +Our outbound HTTP adapters now delegate to Spring's `RestTemplate` for executing the HTTP request and handling its response. +This also means that you can reuse any custom `HttpMessageConverter` implementations. +See "`<>`" for more details. [[new-eip]] ==== Enterprise Integration Pattern Additions -Also in 2.0 we have added support for even more of the patterns described in Hohpe and Woolf's http://www.eaipatterns.com/[Enterprise Integration Patterns] book. +Also in 2.0, we have added support for even more of the patterns described in Hohpe and Woolf's http://www.eaipatterns.com/[Enterprise Integration Patterns] book. [[new-message-history]] ===== Message History -We now provide support for the http://www.eaipatterns.com/MessageHistory.html[Message History] pattern allowing you to keep track of all traversed components, including the name of each channel and endpoint as well as the timestamp of that traversal. -See <> for more details. +We now provide support for the http://www.eaipatterns.com/MessageHistory.html[message history] pattern, letting you keep track of all traversed components, including the name of each channel and endpoint as well as the timestamp of that traversal. +See "`<>`" for more details. [[new-message-store]] ===== Message Store -We now provide support for the http://www.eaipatterns.com/MessageStore.html[Message Store] pattern. -The Message Store provides a strategy for persisting messages on behalf of any process whose scope extends beyond a single transaction, such as the Aggregator and Resequencer. -Many sections of this document provide samples on how to use a Message Store as it affects several areas of Spring Integration. -See <>, <>, <>, <>, <>, and <> for more details +We now provide support for the http://www.eaipatterns.com/MessageStore.html[message store] pattern. +The message store provides a strategy for persisting messages on behalf of any process whose scope extends beyond a single transaction, such as the aggregator and the resequencer. +Many sections of this guide include samples of how to use a message store, as it affects several areas of Spring Integration. +See "`<>`", "`<>`", "`<>`", "`<>`", "`<>`", and "`<>`" for more details. [[new-claim-check]] ===== Claim Check -We have added an implementation of the http://www.eaipatterns.com/StoreInLibrary.html[Claim Check] pattern. -The idea behind the Claim Check pattern is that you can exchange a Message payload for a "claim ticket" and vice-versa. -This allows you to reduce bandwidth and/or avoid potential security issues when sending Messages across channels. -See <> for more details. +We have added an implementation of the http://www.eaipatterns.com/StoreInLibrary.html[claim check] pattern. +The idea behind the claim check pattern is that you can exchange a message payload for a "`claim ticket`". +This lets you reduce bandwidth and avoid potential security issues when sending messages across channels. +See "`<>`" for more details. [[new-control-bus]] ===== Control Bus -We have provided implementations of the http://www.eaipatterns.com/ControlBus.html[Control Bus] pattern which allows you to use messaging to manage and monitor endpoints and channels. -The implementations include both a SpEL-based approach and one that executes Groovy scripts. -See <> and <> for more details. +We have provided implementations of the http://www.eaipatterns.com/ControlBus.html[control bus] pattern, which lets you use messaging to manage and monitor endpoints and channels. +The implementations include both a SpEL-based approach and one that runs Groovy scripts. +See "`<>`" and "`<>`" for more details. [[new-adapters]] ==== New Channel Adapters and Gateways -We have added several new Channel Adapters and Messaging Gateways in Spring Integration 2.0. +We have added several new channel adapters and messaging gateways in Spring Integration 2.0. [[new-ip]] -===== TCP/UDP Adapters +===== TCP and UDP Adapters -We have added Channel Adapters for receiving and sending messages over the TCP and UDP internet protocols. -See <> for more details. -Also, you can checkout the following blog: http://blog.springsource.com/2010/03/29/using-udp-and-tcp-adapters-in-spring-integration-2-0-m3/[TCP/UDP support] +We have added channel adapters for receiving and sending messages over the TCP and UDP internet protocols. +See "`<>`" for more details. +See also the following blog: http://blog.springsource.com/2010/03/29/using-udp-and-tcp-adapters-in-spring-integration-2-0-m3/["`Using UDP and TCP Adapters in Spring Integration 2.0 M3`"]. [[new-twitter]] ===== Twitter Adapters -Twitter adapters provides support for sending and receiving Twitter Status updates as well as Direct Messages. -You can also perform Twitter Searches with an inbound Channel Adapter. -See <> for more details. +Twitter adapters provide support for sending and receiving Twitter status updates and direct messages. +You can also perform Twitter searches with an inbound channel adapter. +See "`<>`" for more details. [[new-xmpp]] ===== XMPP Adapters -The new XMPP adapters support both Chat Messages and Presence events. -See <> for more details. +The new XMPP adapters support both chat messages and presence events. +See "`<>`" for more details. [[new-ftp]] -===== FTP/FTPS Adapters +===== FTP and FTPS Adapters -Inbound and outbound File transfer support over FTP/FTPS is now available. -See <> for more details. +Inbound and outbound file transfer support over FTP and FTPS is now available. +See "`<>`" for more details. [[new-sftp]] ===== SFTP Adapters -Inbound and outbound File transfer support over SFTP is now available. -See <> for more details. +Inbound and outbound file transfer support over SFTP is now available. +See "`<>`" for more details. [[new-feed]] ===== Feed Adapters -We have also added Channel Adapters for receiving news feeds (ATOM/RSS). -See <> for more details. +We have also added channel adapters for receiving news feeds (ATOM and RSS). +See "`<>`" for more details. [[new-other]] ==== Other Additions +Spring Integration adds a number of other features. This section describes them. [[new-groovy]] ===== Groovy Support -With Spring Integration 2.0 we've added Groovy support allowing you to use Groovy scripting language to provide integration and/or business logic. -See <> for more details. +Spring Integration 2.0 added Groovy support, letting you use the Groovy scripting language to provide integration and business logic. +See "`<>`" for more details. [[new-map-transformer]] ===== Map Transformers -These symmetrical transformers convert payload objects to and from a Map. -See <> for more details. +These symmetrical transformers convert payload objects to and from `Map` objects. +See "`<>`" for more details. [[new-json-transformer]] ===== JSON Transformers These symmetrical transformers convert payload objects to and from JSON. -See <> for more details. +See "`<>`" for more details. [[new-serialize-transformer]] ===== Serialization Transformers These symmetrical transformers convert payload objects to and from byte arrays. -They also support the Serializer and Deserializer strategy interfaces that have been added as of Spring 3.0.5. -See <> for more details. +They also support the serializer and deserializer strategy interfaces that Spring 3.0.5 added. +See "`<>`" for more details. [[new-refactoring]] ==== Framework Refactoring The core API went through some significant refactoring to make it simpler and more usable. -Although we anticipate that the impact to the end user should be minimal, please read through this document to find what was changed. -Especially, visit <> , <>, <>, <>, and <> for more details. -If you are depending directly on some of the core components (Message, MessageHeaders, MessageChannel, MessageBuilder, etc.), you will notice that you need to update any import statements. -We restructured some packaging to provide the flexibility we needed for extending the domain model while avoiding any cyclical dependencies (it is a policy of the framework to avoid such "tangles"). +Although we anticipate that the impact to developers should be minimal, you should read through this document to find what was changed. +Specifically, you should read "`<>`", "`<>`", "`<>`", "`<>`", and "`<>`". +If you directly depend on some of the core components (`Message`, `MessageHeaders`, `MessageChannel`, `MessageBuilder`, and others), you need to update any import statements. +We restructured some packaging to provide the flexibility we needed for extending the domain model while avoiding any cyclical dependencies (it is a policy of the framework to avoid such "`tangles`"). [[new-infrastructure]] ==== New Source Control Management and Build Infrastructure -With Spring Integration 2.0 we have switched our build environment to use Git for source control. -To access our repository simply follow this URL: http://git.springsource.org/spring-integration[http://git.springsource.org/spring-integration]. +With Spring Integration 2.0, we switched our build environment to use Git for source control. +To access our repository, visit http://git.springsource.org/spring-integration. We have also switched our build system to http://gradle.org/[Gradle]. [[new-samples]] ==== New Spring Integration Samples -With Spring Integration 2.0 we have decoupled the samples from our main release distribution. -Please read this blog to get more info http://blog.springsource.com/2010/09/29/new-spring-integration-samples/[New Spring Integration Samples] We have also created many new samples, including samples for every new Adapter. +With Spring Integration 2.0, we have decoupled the samples from our main release distribution. +Please read the following blog to get more information: http://blog.springsource.com/2010/09/29/new-spring-integration-samples/[New Spring Integration Samples]. We have also created many new samples, including samples for every new adapter. [[new-sts]] ==== Spring Tool Suite Visual Editor for Spring Integration There is an amazing new visual editor for Spring Integration included within the latest version of SpringSource Tool Suite. -If you are not already using STS, please download it here: - -https://spring.io/tools/sts[Spring Tool Suite] +If you are not already using STS, you can download it athttps://spring.io/tools/sts[Spring Tool Suite]. diff --git a/src/reference/asciidoc/changes-2.0-2.1.adoc b/src/reference/asciidoc/changes-2.0-2.1.adoc index 206c73f4f4..96cce12850 100644 --- a/src/reference/asciidoc/changes-2.0-2.1.adoc +++ b/src/reference/asciidoc/changes-2.0-2.1.adoc @@ -1,68 +1,70 @@ [[migration-2.0-2.1]] === Changes between 2.0 and 2.1 +See the https://github.com/spring-projects/spring-integration/wiki/Spring-Integration-2.0-to-2.1-Migration-Guide[Migration Guide] for important changes that might affect your applications. + [[x2.1-new-components]] ==== New Components +Version 2.1 added a number of new components. + [[x2.1-new-scripting-support]] ===== JSR-223 Scripting Support -In Spring Integration 2.0, support for http://groovy.codehaus.org/[Groovy] was added. -With Spring Integration 2.1 we expanded support for additional languages substantially by implementing support for http://www.jcp.org/en/jsr/detail?id=223[JSR-223] (Scripting for the Javaâ„¢ Platform). +In Spring Integration 2.0, we added support for http://groovy.codehaus.org/[Groovy]. +With Spring Integration 2.1, we expanded support for additional languages substantially by implementing support for http://www.jcp.org/en/jsr/detail?id=223[JSR-223] ("`Scripting for the Javaâ„¢ Platform`"). Now you have the ability to use any scripting language that supports JSR-223 including: * Javascript -* Ruby/JRuby -* Python/Jython +* Ruby and JRuby +* Python and Jython * Groovy - - -For further details please see <>. +For further details, see "`<>`". [[x2.1-new-gemfire-support]] ===== GemFire Support Spring Integration provides support for http://www.vmware.com/products/application-platform/vfabric-gemfire/overview.html[GemFire] by providing inbound adapters for entry and continuous query events, an outbound adapter to write entries to the cache, and http://static.springsource.org/spring-integration/api/org/springframework/integration/store/MessageStore.html[`MessageStore`] and http://static.springsource.org/spring-integration/api/org/springframework/integration/store/MessageGroupStore.html[`MessageGroupStore`] implementations. -Spring integration leverages the http://www.springsource.org/spring-gemfire[_Spring Gemfire_] project, providing a thin wrapper over its components. +Spring integration leverages the http://www.springsource.org/spring-gemfire[Spring Gemfire] project, providing a thin wrapper over its components. -For further details please see <>. +For further details, see "`<>`". [[x2.1-new-amqp-support]] ===== AMQP Support -Spring Integration 2.1 adds several Channel Adapters for receiving and sending messages using thehttp://www.amqp.org/[_Advanced Message Queuing Protocol_] (AMQP). -Furthermore, Spring Integration also provides a point-to-point Message Channel, as well as a publish/subscribe Message Channel that are backed by AMQP Exchanges and Queues. +Spring Integration 2.1 added several channel adapters for receiving and sending messages by using the http://www.amqp.org/[Advanced Message Queuing Protocol] (AMQP). +Furthermore, Spring Integration also provides a point-to-point message channel and a publish-subscribe message channel, both of which are backed by AMQP Exchanges and Queues. -For further details please see <>. +For further details, see "`<>`". [[x2.1-new-mongodb-support]] ===== MongoDB Support -As of version 2.1 Spring Integration provides support for http://www.mongodb.org/[MongoDB] by providing a MongoDB-based MessageStore. +As of version 2.1, Spring Integration provides support for http://www.mongodb.org/[MongoDB] by providing a MongoDB-based `MessageStore`. -For further details please see <>. +For further details, see "`<>`". [[x2.1-new-redis-support]] ===== Redis Support -As of version 2.1 Spring Integration supports http://redis.io/[Redis], an advanced key-value store, by providing a Redis-based MessageStore as well as Publish-Subscribe Messaging adapters. +As of version 2.1, Spring Integration supports http://redis.io/[Redis], an advanced key-value store, by providing a Redis-based `MessageStore` as well as publish-subscribe messaging adapters. -For further details please see <>. +For further details, see "`<>`". [[x2.1-new-resource-support]] ===== Support for Spring's Resource abstraction -As of version 2.1, we've introduced a new _Resource Inbound Channel Adapter_ that builds upon Spring's Resource abstraction to support greater flexibility across a variety of actual types of underlying resources, such as a file, a URL, or a class path resource. -Therefore, it's similar to but more generic than the _File Inbound Channel Adapter_. +In version 2.1, we introduced a new resource inbound channel adapter that builds upon Spring's resource abstraction to support greater flexibility across a variety of actual types of underlying resources, such as a file, a URL, or a classpath resource. +Therefore, it is similar to but more generic than the file inbound channel adapter. -For further details please see <>. +For further details, see "`<>`". [[x2.1-new-stored-proc-support]] ===== Stored Procedure Components -With Spring Integration 2.1, the `JDBC` Module also provides Stored Procedure support by adding several new components, including inbound/outbound channel adapters and an Outbound Gateway. -The Stored Procedure support leverages Spring'shttp://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/jdbc/core/simple/SimpleJdbcCall.html[`SimpleJdbcCall`] class and consequently supports stored procedures for: +With Spring Integration 2.1, the `JDBC` Module also provides stored procedure support by adding several new components, including inbound and outbound channel adapters and an outbound gateway. +The stored procedure support leverages Spring's http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/jdbc/core/simple/SimpleJdbcCall.html[`SimpleJdbcCall`] class and consequently supports stored procedures for: * Apache Derby * DB2 @@ -72,89 +74,89 @@ The Stored Procedure support leverages Spring'shttp://static.springsource.org/sp * PostgreSQL * Sybase - - -The Stored Procedure components also support Sql Functions for the following databases: +The stored procedure components also support SQL functions for the following databases: * MySQL * Microsoft SQL Server * Oracle * PostgreSQL - - -For further details please see <>. +For further details, see "`<>`". [[x2.1-new-xpath-filter-support]] ===== XPath and XML Validating Filter -Spring Integration 2.1 provides a new XPath-based Message Filter, that is part of the `XML` module. -The XPath Filter allows you to filter messages using provided XPath Expressions. -Furthermore, documentation was added for the XML Validating Filter. +Spring Integration 2.1 provides a new XPath-based message filter. +It is part of the `XML` module. +The XPath filter lets you filter messages by using XPath Expressions. +We also added documentation for the XML validating filter. -For more details please see <> and <>. +For more details, see "`<>`" and "`<>`". [[x2.1-new-payload-enricher-support]] ===== Payload Enricher -Since Spring Integration 2.1, the Payload Enricher is provided. -A Payload Enricher defines an endpoint that typically passes ahttp://static.springsource.org/spring-integration/api/org/springframework/integration/Message.html[`Message`] to the exposed request channel and then expects a reply message. +Since Spring Integration 2.1, we added the payload enricher. +A payload enricher defines an endpoint that typically passes a http://static.springsource.org/spring-integration/api/org/springframework/integration/Message.html[`Message`] to the exposed request channel and then expects a reply message. The reply message then becomes the root object for evaluation of expressions to enrich the target payload. -For further details please see <>. +For further details, see "`<>`". [[x2.1-new-ftp-outbound-gateway]] ===== FTP and SFTP Outbound Gateways -Spring Integration 2.1 provides two new Outbound Gateways in order to interact with remote File Transfer Protocol (FTP) or Secure File Transfer Protocol (SFT) servers. -These two gateways allow you to directly execute a limited set of remote commands. +Spring Integration 2.1 provides two new outbound gateways to interact with remote File Transfer Protocol (FTP) or Secure File Transfer Protocol (SFT) servers. +These two gateways let you directly execute a limited set of remote commands. -For instance, you can use these Outbound Gateways to list, retrieve and delete remote files and have the Spring Integration message flow continue with the remote server's response. +For instance, you can use these outbound gateways to list, retrieve, and delete remote files and have the Spring Integration message flow continue with the remote server's response. -For further details please see <> and <>. +For further details, see "`<>`" and "`<>`". [[x2.1-new-ftp-session-caching]] ===== FTP Session Caching -As of version 2.1, we have exposed more flexibility with regards to session management for remote file adapters (e.g., FTP, SFTP etc). +As of version 2.1, we have exposed more flexibility with regards to session management for remote file adapters (for example, FTP, SFTP, and others). -Specifically, the `cache-sessions` attribute, which is available via the XML namespace support, is now _deprecated_. -Alternatively, we added the `sessionCacheSize` and `sessionWaitTimeout` attributes on the `CachingSessionFactory`. +Specifically, we deprecated the `cache-sessions` attribute (which is available via the XML namespace support). +As an alternative, we added the `sessionCacheSize` and `sessionWaitTimeout` attributes on the `CachingSessionFactory`. -For further details please see <> and <>. +For further details, see "`<>`" and "`<>`". [[x2.1-framework-refactorings]] ==== Framework Refactoring +We refactored the Spring Integration framework in a number of ways, all described in this section. + [[x2.1-router-standardization]] ===== Standardizing Router Configuration -Router parameters have been standardized across all router implementations with Spring Integration 2.1 providing a more consistent user experience. +We standardized router parameters across all router implementations with Spring Integration 2.1 to provide a more consistent user experience. -With Spring Integration 2.1 the `ignore-channel-name-resolution-failures` attribute has been removed in favor of consolidating its behavior with the `resolution-required` attribute. +In Spring Integration 2.1, we removed the `ignore-channel-name-resolution-failures` attribute in favor of consolidating its behavior with the `resolution-required` attribute. Also, the `resolution-required` attribute now defaults to `true`. -Starting with Spring Integration 2.1, routers will no longer silently drop any messages, if no default output channel was defined. -This means, that by default routers now require at least one resolved channel (if no `default-output-channel` was set) and by default will throw a `MessageDeliveryException` if no channel was determined (or an attempt to send was not successful). +Starting with Spring Integration 2.1, routers no longer silently drop any messages if no default output channel was defined. +This means that, by default, routers now require at least one resolved channel (if no `default-output-channel` was set) and, by default, throw a `MessageDeliveryException` if no channel was determined (or an attempt to send was not successful). -If, however, you do desire to drop messages silently, simply set `default-output-channel="nullChannel"`. +If, however, you do want to drop messages silently, you can set `default-output-channel="nullChannel"`. -IMPORTANT: With the standardization of Router parameters and the consolidation of the parameters described above, there is the possibility of breaking older Spring Integration based applications. +IMPORTANT: With the standardization of router parameters and the consolidation of the parameters described earlier, older Spring Integration based applications may break. -For further details please see <> +For further details, see `<>`. [[x2.1-schema-updated]] ===== XML Schemas updated to 2.1 -Spring Integration 2.1 ships with an updated XML Schema (version 2.1), providing many improvements, e.g. -the Router standardizations discussed above. +Spring Integration 2.1 ships with an updated XML Schema (version 2.1). +It provides many improvements, such as the Router standardizations <>. -From now on, users _must_ always declare the latest XML schema (currently version 2.1). +From now on, developers must always declare the latest XML schema (currently version 2.1). Alternatively, they can use the version-less schema. -Generally, the best option is to use version-less namespaces, as these will automatically use the latest available version of Spring Integration. +Generally, the best option is to use version-less namespaces, as these automatically use the latest available version of Spring Integration. -Declaring a version-less Spring Integration namespace: +The following example declares a version-less Spring Integration namespace: +==== [source,xml] ---- @@ -168,9 +170,11 @@ Declaring a version-less Spring Integration namespace: ... ---- +==== -Declaring a Spring Integration namespace using an explicit version: +The following example declares a Spring Integration namespace with an explicit version: +==== [source,xml] ---- @@ -184,37 +188,37 @@ Declaring a Spring Integration namespace using an explicit version: ... ---- +==== -The old 1.0 and 2.0 schemas are still there, but if an Application Context still references one of those deprecated schemas, the validator will fail on initialization. +The old 1.0 and 2.0 schemas are still there. +However, if an application context still references one of those deprecated schemas, the validator fails on initialization. [[x2.1-source-control-infrastructure]] ==== Source Control Management and Build Infrastructure +Version 2.1 introduced a number of changes to source control management and build infrastructure. +This section covers those changes. + [[x2.1-move-to-github]] -===== Source Code now hosted on Github +===== Source Code Now Hosted on Github Since version 2.0, the Spring Integration project uses http://git-scm.com/[Git] for version control. -In order to increase community visibility even further, the project was moved from SpringSource hosted Git repositories to http://www.github.com/[Github]. +To increase community visibility even further, the project was moved from SpringSource hosted Git repositories to http://www.github.com/[Github]. The Spring Integration Git repository is located at: https://github.com/spring-projects/spring-integration[spring-integration]. -For the project we also improved the process of providing code contributions and we ensure that every commit is peer-reviewed. +For the project, we also improved the process of providing code contributions. +Further, we ensure that every commit is peer-reviewed. In fact, core committers now follow the same process as contributors. -For more details please see: - -https://github.com/spring-projects/spring-integration/blob/master/CONTRIBUTING.adoc[Contributing]. +For more details, see https://github.com/spring-projects/spring-integration/blob/master/CONTRIBUTING.adoc[Contributing]. [[x2.1-sonar]] ===== Improved Source Code Visibility with Sonar -In an effort to provide better source code visibility and consequently to monitor the quality of Spring Integration's source code, an instance of http://www.sonarsource.org/[Sonar] was setup and metrics are gathered nightly and made available at: - -https://sonar.spring.io/dashboard?id=org.springframework.integration%3Aspring-integration%3Amaster[sonar.spring.io]. +In an effort to provide better source code visibility and consequently to monitor the quality of Spring Integration's source code, we set up an instance of http://www.sonarsource.org/[Sonar]. +We gather metrics nightly and make them available at https://sonar.spring.io/dashboard?id=org.springframework.integration%3Aspring-integration%3Amaster[sonar.spring.io]. [[x2.1-new-samples]] ==== New Samples -For the 2.1 release of Spring Integration we also expanded the Spring Integration Samples project and added many new samples, e.g. -samples covering AMQP support, the new payload enricher, a sample illustrating techniques for testing Spring Integration flow fragments, as well as an example for executing Stored Procedures against Oracle. -For details please visit: - -https://github.com/spring-projects/spring-integration-samples[spring-integration-samples]. +For the 2.1 release of Spring Integration, we also expanded the Spring Integration Samples project and added many new samples, such as samples that cover AMQP support, a sample that showcases the new payload enricher, a sample illustrating techniques for testing Spring Integration flow fragments, and a sample for executing stored procedures against Oracle databases. +For details, visit https://github.com/spring-projects/spring-integration-samples[spring-integration-samples]. diff --git a/src/reference/asciidoc/changes-2.1-2.2.adoc b/src/reference/asciidoc/changes-2.1-2.2.adoc index 0d04817dc4..d1d6b48161 100644 --- a/src/reference/asciidoc/changes-2.1-2.2.adoc +++ b/src/reference/asciidoc/changes-2.1-2.2.adoc @@ -1,20 +1,25 @@ [[migration-2.1-2.2]] === Changes between 2.1 and 2.2 +See the https://github.com/spring-projects/spring-integration/wiki/Spring-Integration-2.1-to-2.2-Migration-Guide[Migration Guide] for important changes that might affect your applications. +You can find migration guides for all versions back to 2.1 on the https://github.com/spring-projects/spring-integration/wiki[wiki]. + [[x2.2-new-components]] ==== New Components -[[x2.2-redis-store-adapters]] -===== RedisStore Inbound and Outbound Channel Adapters +Version 2.2 added a number of new components. -Spring Integration now has RedisStore Inbound and Outbound Channel Adapters allowing you to write and read Message payloads to/from Redis collection(s). -For more information please see <> and <>. +[[x2.2-redis-store-adapters]] +===== `RedisStore` Inbound and Outbound Channel Adapters + +Spring Integration now has `RedisStore` Inbound and Outbound Channel Adapters, letting you write and read `Message` payloads to and from Redis collections. +For more information, see "`<>`" and "`<>`". [[x2.2-mongo-adapters]] ===== MongoDB Inbound and Outbound Channel Adapters -Spring Integration now has MongoDB Inbound and Outbound Channel Adapters allowing you to write and read Message payloads to/from a MongoDB document store. -For more information please see <> and <>. +Spring Integration now has MongoDB inbound and outbound channel adapters, letting you write and read `Message` payloads to and from a MongoDB document store. +For more information, see "`<>`" and "`<>`". [[x2.2-jpa]] ===== JPA Endpoints @@ -22,18 +27,18 @@ For more information please see <> and <>_ -* _<>_ -* _<>_ -* _<>_ +* <> +* <> +* <> +* <> - - -For more information please see <> +For more information, see "`<>`". [[x2.2-general]] ==== General Changes +This section describes general changes from version 2.1 to version 2.2. + [[x2.2-spring-31]] ===== Spring 3.1 Used by Default @@ -42,134 +47,124 @@ Spring Integration now uses Spring 3.1. [[x2.2-handler-advice]] ===== Adding Behavior to Endpoints -The ability to add an to a poller has been available for some time. +The ability to add an `` to a poller has been available for some time. However, the behavior added by this affects the entire integration flow. -It did not address the ability to add, say, retry, to an individual endpoint. -The 2.2. -release introduces the to many endpoints. +It did not address the ability to add (for example) retry to an individual endpoint. +The 2.2. release introduced the `` to many endpoints. -In addition, 3 standard Advice classes have been provided for this purpose: +In addition, we added three standard advice classes for this purpose: -* MessageHandlerRetryAdvice -* MessageHandlerCircuitBreakerAdvice -* ExpressionEvaluatingMessageHandlerAdvice +* `MessageHandlerRetryAdvice` +* `MessageHandlerCircuitBreakerAdvice` +* `ExpressionEvaluatingMessageHandlerAdvice` - - -For more information, see <>. +For more information, see "`<>`". [[x2.2-transaction-sync]] ===== Transaction Synchronization and Pseudo Transactions -Pollers can now participate in Spring's _Transaction Synchronization_ feature. -This allows for synchronizing such operations as renaming files by an inbound channel adapter depending on whether the transaction commits, or rolls back. +Pollers can now participate in Spring's Transaction Synchronization feature. +This allows for synchronizing such operations as renaming files by an inbound channel adapter, depending on whether the transaction commits or rolls back. -In addition, these features can be enabled when there is not a 'real' transaction present, by means of a `PseudoTransactionManager`. +In addition, you can enable these features when no "`real`" transaction is present, by means of a `PseudoTransactionManager`. -For more information see <>. +For more information, see "`<>`". [[x2.2-file-adapter]] -===== File Adapter - Improved File Overwrite/Append Handling +===== File Adapter: Improved File Overwrite and Append Handling -When using the _File Oubound Channel Adapter_ or the _File Outbound Gateway_, a new _mode_ property was added. -Prior to _Spring Integration 2.2_, target files were replaced when they existed. +When using the file outbound channel adapter or the file outbound gateway, you can use a new `mode` property. +Prior to Spring Integration 2.2, target files were replaced when they existed. Now you can specify the following options: -* REPLACE (Default) -* APPEND -* FAIL -* IGNORE +* `REPLACE` (default) +* `APPEND` +* `FAIL` +* `IGNORE` - - -For more information please see <>. +For more information, see "`<>`". [[x2.2-outbound-gateways]] -===== Reply-Timeout added to more Outbound Gateways +===== Reply-Timeout Added to More Outbound Gateways -The XML Namespace support adds the _reply-timeout_ attribute to the following _Outbound Gateways_: +The XML Namespace support adds the reply-timeout attribute to the following outbound gateways: -* Amqp Outbound Gateway +* AMQP Outbound Gateway * File Outbound Gateway -* Ftp Outbound Gateway -* Sftp Outbound Gateway -* Ws Outbound Gateway - - +* FTP Outbound Gateway +* SFTP Outbound Gateway +* WS Outbound Gateway [[x2.2-amqp-11]] ===== Spring-AMQP 1.1 Spring Integration now uses Spring AMQP 1.1. -This enables several features to be used within a Spring Integration application, including... +This enables several features to be used within a Spring Integration application, including the following: * A fixed reply queue for the outbound gateway * HA (mirrored) queues -* Publisher Confirms -* Returned Messages -* Support for Dead Letter Exchanges/Dead Letter Queues - - +* Publisher confirmations +* Returned messages +* Support for dead letter exchanges and dead letter queues [[x2.2-jdbc-11]] ===== JDBC Support - Stored Procedures Components -_SpEL Support_ +====== SpEL Support -When using the Stored Procedure components of the Spring Integration JDBC Adapter, you can now provide Stored Procedure Names or Stored Function Names using Spring Expression Language (SpEL). +When using the stored procedure components of the Spring Integration JDBC Adapter, you can now provide stored procedure names or stored function names by using the Spring Expression Language (SpEL). -This allows you to specify the Stored Procedures to be invoked at runtime. -For example, you can provide Stored Procedure names that you would like to execute via Message Headers. -For more information please see <>. +Doing so lets you specify the stored procedures to be invoked at runtime. +For example, you can provide stored procedure names that you would like to execute through message headers. +For more information, see "`<>`". -_JMX Support_ - -The Stored Procedure components now provide basic JMX support, exposing some of their properties as MBeans: - -* Stored Procedure Name -* Stored Procedure Name Expression -* JdbcCallOperations Cache Statistics +====== JMX Support +The stored procedure components now provide basic JMX support, exposing some of their properties as MBeans: +* Stored procedure name +* Stored procedure name expression +* `JdbcCallOperations` cache statistics [[x2.2-jdbc-gateway-update-optional]] -===== JDBC Support - Outbound Gateway +===== JDBC Support: Outbound Gateway -When using the JDBC Outbound Gateway, the update query is no longer mandatory. -You can now provide solely a select query using the request message as a source of parameters. +When you use the JDBC outbound gateway, the update query is no longer mandatory. +You can now provide only a select query by using the request message as a source of parameters. [[x2.2-jdbc-message-store-channels]] -===== JDBC Support - Channel-specific Message Store Implementation +===== JDBC Support: Channel-specific Message Store Implementation -A new _Message Channel_-specific Message Store Implementation has been added, providing a more scalable solution using database-specific SQL queries. -For more information please see: <>. +We added a new message channel-specific message store implementation, providing a more scalable solution using database-specific SQL queries. +For more information, see "`<>`". [[x2.2-shutdown]] ===== Orderly Shutdown -A method `stopActiveComponents()` has been added to the IntegrationMBeanExporter. -This allows a Spring Integration application to be shut down in an orderly manner, disallowing new inbound messages to certain adapters and waiting for some time to allow in-flight messages to complete. +We added a method called `stopActiveComponents()` to the `IntegrationMBeanExporter`. +It allows a Spring Integration application to be shut down in an orderly manner, disallowing new inbound messages to certain adapters and waiting for some time to allow in-flight messages to complete. [[x2.2-jms-og]] -===== JMS Oubound Gateway Improvements +===== JMS Outbound Gateway Improvements -The JMS Outbound Gateway can now be configured to use a `MessageListener` container to receive replies. -This can improve performance of the gateway. +You can now configure the JMS outbound gateway to use a `MessageListener` container to receive replies. +Doing so can improve performance of the gateway. [[x2.2-o-t-j-t]] -===== object-to-json-transformer +===== `ObjectToJsonTransformer` -The `ObjectToJsonTransformer` now sets the _content-type_ header to _application/json_ by default. -For more information see <>. +By default, the `ObjectToJsonTransformer` now sets the `content-type` header to `application/json`. +For more information, see "`<>`". [[httpChanges]] ===== HTTP Support Java serialization over HTTP is no longer enabled by default. -Previously, when setting a `expected-response-type` to a `Serializable` object, the `Accept` header was not properly set up. -The `SerializingHttpMessageConverter` has now been updated to set the Accept header to `application/x-java-serialized-object`. -However, because this could cause incompatibility with existing applications, it was decided to no longer automatically add this converter to the HTTP endpoints. +Previously, when setting an `expected-response-type` on a `Serializable` object, the `Accept` header was not properly set up. +We updated the `SerializingHttpMessageConverter` to set the `Accept` header to `application/x-java-serialized-object`. +However, because this could cause incompatibility with existing applications, we decided to no longer automatically add this converter to the HTTP endpoints. -If you wish to use Java serialization, you will need to add the `SerializingHttpMessageConverter` to the appropriate endpoints, using the `message-converters` attribute, when using XML configuration, or using the `setMessageConverters()` method. +If you wish to use Java serialization, you need to add the `SerializingHttpMessageConverter` to the appropriate endpoints by using the `message-converters` attribute (when you use XML configuration) or by using the `setMessageConverters()` method (in Java). -Alternatively, you may wish to consider using JSON instead which is enabled by simply having `Jackson` on the classpath. +Alternatively, you may wish to consider using JSON instead. +It is enabled by having `Jackson` on the classpath. diff --git a/src/reference/asciidoc/changes-2.2-3.0.adoc b/src/reference/asciidoc/changes-2.2-3.0.adoc index 19ef947bc8..91abbfb048 100644 --- a/src/reference/asciidoc/changes-2.2-3.0.adoc +++ b/src/reference/asciidoc/changes-2.2-3.0.adoc @@ -1,160 +1,173 @@ [[migration-2.2-3.0]] === Changes Between 2.2 and 3.0 +See the https://github.com/spring-projects/spring-integration/wiki/Spring-Integration-2.2-to-3.0-Migration-Guide[Migration Guide] for important changes that might affect your applications. +You can find migration guides for all versions back to 2.1 on the https://github.com/spring-projects/spring-integration/wiki[wiki]. + [[x3.0-new-components]] ==== New Components +Version 3.0 added a number of new components. + [[x3.0-request-mapping]] ===== HTTP Request Mapping -The HTTP module now provides powerful Request Mapping support for Inbound Endpoints. -Class `UriPathHandlerMapping` was replaced by `IntegrationRequestMappingHandlerMapping`, which is registered under the bean name `integrationRequestMappingHandlerMapping` in the application context. -Upon parsing of the HTTP Inbound Endpoint, a new `IntegrationRequestMappingHandlerMapping` bean is either registered or an existing bean is being reused. -To achieve flexible Request Mapping configuration, Spring Integration provides the `` sub-element for the `` and the ``. -Both HTTP Inbound Endpoints are now fully based on the Request Mapping infrastructure that was introduced with Spring MVC 3.1. +The HTTP module now provides powerful request mapping support for inbound endpoints. +We replaced the `UriPathHandlerMapping` class with `IntegrationRequestMappingHandlerMapping`, which is registered under the bean name of `integrationRequestMappingHandlerMapping` in the application context. +Upon parsing of the HTTP inbound endpoint, either a new `IntegrationRequestMappingHandlerMapping` bean is registered or an existing bean is reused. +To achieve flexible request mapping configuration, Spring Integration provides the `` child element for `` and the ``. +Both HTTP inbound endpoints are now fully based on the request mapping infrastructure that was introduced with Spring MVC 3.1. For example, multiple paths are supported on a single inbound endpoint. -For more information see <>. +For more information see "`<>`". [[x3.0-spel-customization]] ===== Spring Expression Language (SpEL) Configuration -A new `IntegrationEvaluationContextFactoryBean` is provided to allow configuration of custom `PropertyAccessor` s and functions for use in SpEL expressions throughout the framework. -For more information see <>. +We added a new `IntegrationEvaluationContextFactoryBean` to allow configuration of custom `PropertyAccessor` implementations and functions for use in SpEL expressions throughout the framework. +For more information, see "`<>`". [[x3.0-spel-functions]] ===== SpEL Functions Support -To customize the SpEL `EvaluationContext` with static `Method` functions, the new `` component is introduced. -Two built-in functions are also provided (`#jsonPath` and `#xpath`). -For more information see <>. +To customize the SpEL `EvaluationContext` with static `Method` functions, we introduced the `` component. +We also added two built-in functions: `#jsonPath` and `#xpath`. +For more information, see "`<>`". [[x3.0-spel-property-accessors]] ===== SpEL PropertyAccessors Support -To customize the SpEL `EvaluationContext` with `PropertyAccessor` implementations the new `` component is introduced. -For more information see <>. +To customize the SpEL `EvaluationContext` with `PropertyAccessor` implementations, we added the `` component. +For more information, see "`<>`". [[x3.0-redis-new-components]] ===== Redis: New Components -A new Redis-based http://docs.spring.io/spring-integration/docs/latest-ga/api/org/springframework/integration/store/MetadataStore.html[MetadataStore] implementation has been added. -The `RedisMetadataStore` can be used to maintain state of a `MetadataStore` across application restarts. -This new `MetadataStore` implementation can be used with adapters such as: +We added a new Redis-based http://docs.spring.io/spring-integration/docs/latest-ga/api/org/springframework/integration/store/MetadataStore.html[`MetadataStore`] implementation. +You can use the `RedisMetadataStore` to maintain the state of a `MetadataStore` across application restarts. +This new `MetadataStore` implementation can be used with adapters, such as: -* Twitter Inbound Adapters -* Feed Inbound Channel Adapter +* Twitter inbound adapters +* Feed inbound channel adapter +We added new queue-based components. +We added the `` and `` components to perform 'right pop' and 'left push' operations, respectively, on a Redis List. - -New queue-based components have been added. -The `` and the `` components are provided to perform 'right pop' and 'left push' operations on a Redis List, respectively. - -For more information see <>. +For more information, "`see <>`". [[x3.0-hcr]] ===== Header Channel Registry -It is now possible to instruct the framework to store reply and error channels in a registry for later resolution. -This is useful for cases where the `replyChannel` or `errorChannel` might be lost; for example when serializing a message. -See <> for more information. +You can now instruct the framework to store reply channels and error channels in a registry for later resolution. +This is useful for cases where the `replyChannel` or `errorChannel` might be lost (for example, when serializing a message). +See "`<>`" for more information. [[x3.0-configurable-mongo-MS]] -===== MongoDB support: New ConfigurableMongoDbMessageStore +===== MongoDB support: New `ConfigurableMongoDbMessageStore` -In addition to the existing `eMongoDbMessageStore`, a new `ConfigurableMongoDbMessageStore` has been introduced. +In addition to the existing `eMongoDbMessageStore`, we introduced a new `ConfigurableMongoDbMessageStore`. This provides a more robust and flexible implementation of `MessageStore` for MongoDB. -It does not have backward compatibility, with the existing store, but it is recommended to use it for new applications. -Existing applications can use it, but messages in the old store will not be available. -See <> for more information. +It does not have backward compatibility with the existing store, but we recommend using it for new applications. +Existing applications can use it, but messages in the old store are not available. +See "`<>`" for more information. [[x3.0-syslog]] ===== Syslog Support -Building on the 2.2 `SyslogToMapTransformer` Spring Integration 3.0 now introduces `UDP` and `TCP` inbound channel adapters especially tailored for receiving SYSLOG messages. -For more information, see <>. +Building on the 2.2 `SyslogToMapTransformer`, Spring Integration 3.0 introduces `UDP` and `TCP` inbound channel adapters especially tailored for receiving SYSLOG messages. +For more information, see "`<>`". [[x3.0-tail]] -===== 'Tail' Support +===== `tail` Support -File 'tail'ing inbound channel adapters are now provided to generate messages when lines are added to the end of text files; see <>. +We added file inbound channel adapters that use the `tail` command to generate messages when lines are added to the end of text files. +See "`<>`". [[x3.0-jmx]] ===== JMX Support -* A new `` is provided; this adapter queries the JMX MBean tree and sends a message with a payload that is the graph of objects that matches the query. -By default the MBeans are mapped to primitives and simple Objects like Map, List and arrays - permitting simple transformation, for example, to JSON. +We added ``. +This adapter queries the JMX MBean tree and sends a message with a payload that is the graph of objects that match the query. +By default, the MBeans are mapped to primitives and simple Objects (such as `Map`, `List`, and arrays). +It permits simple transformation to, for example, JSON. -* The `IntegrationMBeanExporter` now allows the configuration of a custom `ObjectNamingStrategy` using the `naming-strategy` attribute. +The `IntegrationMBeanExporter` now allows the configuration of a custom `ObjectNamingStrategy` by using the `naming-strategy` attribute. -For more information, see <>. +For more information, see "`<>`". [[x3.0-tcp-events]] ===== TCP/IP Connection Events and Connection Management -`TcpConnection` s now emit `ApplicationEvent` s (specifically `TcpConnectionEvent` s) when connections are opened, closed, or an exception occurs. -This allows applications to be informed of changes to TCP connections using the normal Spring `ApplicationListener` mechanism. +`TcpConnection` instances now emit `ApplicationEvent` instances (specifically `TcpConnectionEvent` instances) when connections are opened or closed or when an exception occurs. +This change lets applications be informed of changes to TCP connections by using the normal Spring `ApplicationListener` mechanism. -`AbstractTcpConnection` has been renamed `TcpConnectionSupport`; custom connections that are subclasses of this class, can use its methods to publish events. -Similarly, `AbstractTcpConnectionInterceptor` has been renamed to `TcpConnectionInterceptorSupport`. +We renamed `AbstractTcpConnection` to `TcpConnectionSupport`. +Custom connections that are subclasses of this class can use its methods to publish events. +Similarly, we renamed `AbstractTcpConnectionInterceptor` to `TcpConnectionInterceptorSupport`. -In addition, a new `` is provided; by default, this adapter sends all `TcpConnectionEvent` s to a `Channel`. +In addition, we added ``. +By default, this adapter sends all `TcpConnectionEvent` instances to a `Channel`. -Further, the TCP Connection Factories, now provide a new method `getOpenConnectionIds()`, which returns a list of identifiers for all open connections; this allows applications, for example, to broadcast to all open connections. +Further, the TCP connection factories now provide a new method called `getOpenConnectionIds()`, which returns a list of identifiers for all open connections. +It lets applications broadcast to all open connections, among other uses. -Finally, the connection factories also provide a new method `closeConnection(String connectionId)` which allows applications to explicitly close a connection using its ID. +Finally, the connection factories also provide a new method called `closeConnection(String connectionId)`, which lets applications explicitly close a connection by using its ID. -For more information see <>. +For more information see "`<>`". [[x3.0-inbound-script]] ===== Inbound Channel Adapter Script Support -The `` now supports `` and `