JIRA: https://jira.spring.io/browse/INT-3416 Add caution to docs about users getting a hard reference to the group instead of a copy.
129 lines
8.2 KiB
XML
129 lines
8.2 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="message-store"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>Message Store</title>
|
|
<para>
|
|
Enterprise Integration Patterns (EIP) identifies several patterns that have the capability to buffer messages. For example,
|
|
an <emphasis>Aggregator</emphasis> buffers messages until they can be released and a <emphasis>QueueChannel</emphasis> buffers
|
|
messages until consumers explicitly receive those messages from that channel.
|
|
Because of the failures that can occur at any point within your message flow, EIP components that buffer
|
|
messages also introduce a point where messages could be lost.
|
|
</para>
|
|
|
|
<para>
|
|
To mitigate the risk of losing Messages, EIP defines the <ulink url="http://eaipatterns.com/MessageStore.html">Message Store</ulink> pattern which allows
|
|
EIP components to store <emphasis>Messages</emphasis> typically in some type of persistent store (e.g. RDBMS).
|
|
</para>
|
|
|
|
<para>
|
|
Spring Integration provides support for the <emphasis>Message Store</emphasis> pattern by
|
|
a) defining a <classname>org.springframework.integration.store.MessageStore</classname> strategy interface,
|
|
b) providing several implementations of this interface, and
|
|
c) exposing a <code>message-store</code> attribute on all components that have the capability to buffer messages
|
|
so that you can inject any instance that implements the <classname>MessageStore</classname> interface.
|
|
</para>
|
|
|
|
<para>Details on how to configure a specific <emphasis>Message Store</emphasis> implementation and/or how to inject
|
|
a <classname>MessageStore</classname> implementation into a specific buffering component are described
|
|
throughout the manual (see the specific component, such as <emphasis>QueueChannel</emphasis>, <emphasis>Aggregator</emphasis>,
|
|
<emphasis>Resequencer</emphasis> etc.), but here are a couple of samples to give you an idea:
|
|
</para>
|
|
|
|
<para>
|
|
QueueChannel
|
|
<programlisting language="xml"><![CDATA[<int:channel id="myQueueChannel">
|
|
<int:queue message-store="refToMessageStore"/>
|
|
<int:channel>]]></programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
Aggregator
|
|
<programlisting language="xml"><![CDATA[<int:aggregator … message-store="refToMessageStore"/>]]></programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
By default <emphasis>Messages</emphasis> are stored in-memory using <classname>org.springframework.integration.store.SimpleMessageStore</classname>,
|
|
an implementation of <classname>MessageStore</classname>. That might be fine for development or simple low-volume environments where the potential loss
|
|
of non-persistent messages is not a concern. However, the typical production application will need a more robust option, not only to mitigate the risk of
|
|
message loss but also to avoid potential out-of-memory errors. Therefore, we also provide MessageStore implementations for a variety of data-stores.
|
|
Below is a complete list of supported implementations:
|
|
|
|
<itemizedlist>
|
|
<listitem><xref linkend="jdbc-message-store"/> - uses RDBMS to store Messages</listitem>
|
|
<listitem><xref linkend="redis-message-store"/> - uses Redis key/value datastore to store Messages</listitem>
|
|
<listitem><xref linkend="mongodb-message-store"/> - uses MongoDB document store to store Messages</listitem>
|
|
<listitem><xref linkend="gemfire-message-store"/> - uses Gemfire distributed cache to store Messages</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>
|
|
<important>
|
|
<para>However be aware of some limitations while using persistent implementations of the <classname>MessageStore</classname>.</para>
|
|
<para>The Message data (payload and headers) is <emphasis>serialized</emphasis> and <emphasis>deserialized</emphasis>
|
|
using different serialization strategies depending on the implementation of the <classname>MessageStore</classname>.
|
|
For example, when using <classname>JdbcMessageStore</classname>, only <classname>Serializable</classname> data is persisted by default.
|
|
In this case non-Serializable headers are removed before serialization occurs.
|
|
Also be aware of the protocol specific headers that are injected by transport adapters (e.g., FTP, HTTP, JMS etc.).
|
|
For example, <literal><http:inbound-channel-adapter/></literal> maps HTTP-headers into Message Headers and one of them is an
|
|
<classname>ArrayList</classname> of non-Serializable <classname>org.springframework.http.MediaType</classname> instances.
|
|
However you are able to inject your own implementation of the <classname>Serializer</classname> and/or
|
|
<classname>Deserializer</classname> strategy interfaces into some <classname>MessageStore</classname> implementations
|
|
(such as JdbcMessageStore) to change the behaviour of serialization and deserialization.
|
|
</para>
|
|
<para>
|
|
Special attention must be paid to the headers that represent certain types of data.
|
|
For example, if one of the headers contains an instance of some <emphasis>Spring Bean</emphasis>, upon deserialization you may end
|
|
up with a different instance of that bean,
|
|
which directly affects some of the implicit headers created by the framework (e.g., REPLY_CHANNEL or ERROR_CHANNEL).
|
|
Currently they are not serializable, but even if they were, the deserialized channel would not represent the expected instance.
|
|
</para>
|
|
<para>
|
|
Beginning with <emphasis>Spring Integration version 3.0</emphasis>, this issue can be resolved with a header enricher,
|
|
configured to replace these headers with a name after registering the channel with the <classname>HeaderChannelRegistry</classname>.
|
|
</para>
|
|
<para>
|
|
Also when configuring a message-flow like this:
|
|
<emphasis>gateway -> queue-channel (backed by a persistent Message Store) -> service-activator</emphasis>
|
|
That gateway creates a <emphasis>Temporary Reply Channel</emphasis>, and it will be lost by the time the
|
|
service-activator's poller reads from the queue. Again, you can use the header enricher to replace the headers with a
|
|
String representation.
|
|
</para>
|
|
<para>
|
|
For more information, refer to the <xref linkend="header-enricher"/>.
|
|
</para>
|
|
</important>
|
|
</para>
|
|
|
|
<para>
|
|
<emphasis>Spring Integration 4.0</emphasis> introduced two new interfaces <interfacename>ChannelMessageStore</interfacename> -
|
|
to implement operations specific for <classname>QueueChannel</classname>s, <interfacename>PriorityCapableChannelMessageStore</interfacename> -
|
|
to mark <interfacename>MessageStore</interfacename> implementation to be used for <classname>PriorityChannel</classname>s and to provide
|
|
<emphasis>priority</emphasis> order for persisted Messages. The real behaviour depends on implementation. The Framework provides these implementations,
|
|
which can be used as a persistent <interfacename>MessageStore</interfacename> for <classname>PriorityChannel</classname>:
|
|
<itemizedlist>
|
|
<listitem><xref linkend="redis-cms"/></listitem>
|
|
<listitem><xref linkend="mongodb-priority-channel-message-store"/></listitem>
|
|
<listitem><xref linkend="jdbc-message-store-channels"/></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<caution id="sms-caution">
|
|
<title>Caution with SimpleMessageStore</title>
|
|
<para>
|
|
Starting with <emphasis>version 4.1</emphasis>, the <classname>SimpleMessageStore</classname> no longer copies
|
|
the message group when calling <code>getMessageGroup()</code>. For large message groups, this was a significant
|
|
performance problem. 4.0.1 introduced a boolean <code>copyOnGet</code> allowing this to be controlled. When
|
|
used internally by the aggregator, this was set to false to improve performance. It is now false by default.
|
|
</para>
|
|
<para>
|
|
Users accessing the group store outside of components such as aggregators, will now get a direct reference
|
|
to the group being used by the aggregator, instead of a copy. Manipulation of the group outside of the aggregator may
|
|
cause unpredictable results.
|
|
</para>
|
|
<para>
|
|
For this reason, users should not perform such manipulation, or set the <code>copyOnGet</code>
|
|
property to <code>true</code>.
|
|
</para>
|
|
</caution>
|
|
</section>
|