JIRA: https://jira.spring.io/browse/INT-2426 INT-2426: pushed `final` modifier fix for Java 6 compatibility INT-2426: Rework logic to the `MetadataStore` INT-2426: `IdempotentReceiver` -> `IdempotentReceiverInterceptor` * Move `Idempotent Filtering` logic to the `IdempotentReceiverInterceptor`, which should be applied as a regular AOP `Advice` to the `MessageHandler#handleMessage` * Provide an xml component `<idempotent-receiver>` * Introduce `IdempotentReceiverAutoProxyCreator` to get deal with `IdempotentReceiverInterceptor` and `MessageHandler`s. The `Proxying` logic is based on the mapping between interceptor and `consumer endpoint` `ids` * Introduce `MetadataStoreSelector` along side with `MetadataKeyStrategy` and `ExpressionMetadataKeyStrategy` implementation INT-2426: Introduce `IdempotentReceiver` annotation Add `IdempotentReceiverIntegrationTests` in the JMX module to be sure that all proxying works well. INT-2426: Polishing according PR comments * Rename `IdempotentReceiverAutoProxyCreatorInitializer` * Add support for several `IRI` for the one `MH` * Polishing JavaDocs INT-2426: Add `What's New` note Doc Polishing. More Doc Polishing Use Timestamp (hex) instead of Id for Value Facilitate cleanup.
79 lines
4.6 KiB
XML
79 lines
4.6 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="metadata-store"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>Metadata Store</title>
|
|
<para>
|
|
Many external systems, services or resources aren't transactional (Twitter, RSS, file system etc.)
|
|
and there is no any ability to mark the data as read. Or there is just need to implement the
|
|
Enterprise Integration Pattern <ulink url="http://eaipatterns.com/IdempotentReceiver.html">Idempotent Receiver</ulink>
|
|
in some integration solutions. To achieve this goal and store some previous state of the Endpoint before the next
|
|
interaction with external system, or deal with the next Message, Spring Integration provides the <emphasis>Metadata Store</emphasis>
|
|
component being an implementation of the <interfacename>org.springframework.integration.metadata.MetadataStore</interfacename>
|
|
interface with a general <emphasis>key-value</emphasis> contract.
|
|
</para>
|
|
<para>
|
|
The <emphasis>Metadata Store</emphasis> is designed to store various types of generic meta-data
|
|
(e.g., published date of the last feed entry that has been processed) to help components such as the Feed adapter deal with duplicates.
|
|
If a component is not directly provided with a reference to a <interfacename>MetadataStore</interfacename>,
|
|
the algorithm for locating a metadata store is as follows: First, look for a bean with id
|
|
<code>metadataStore</code> in the ApplicationContext. If one is found then it will be used, otherwise
|
|
it will create a new instance of <classname>SimpleMetadataStore</classname> which is an in-memory implementation
|
|
that will only persist metadata within the lifecycle of the currently running Application Context. This means
|
|
that upon restart you may end up with duplicate entries.
|
|
</para>
|
|
<para>
|
|
If you need to persist metadata between Application Context restarts, two
|
|
persistent <interfacename>MetadataStores</interfacename> are provided by the framework:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>PropertiesPersistingMetadataStore</listitem>
|
|
<listitem><xref linkend="redis-metadata-store"/></listitem>
|
|
<listitem><xref linkend="gemfire-metadata-store"/></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
The <classname>PropertiesPersistingMetadataStore</classname> is backed by a properties file and a
|
|
<interfacename><ulink url="http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/PropertiesPersister.html">PropertiesPersister</ulink></interfacename>.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[<bean id="metadataStore"
|
|
class="org.springframework.integration.store.PropertiesPersistingMetadataStore"/>]]></programlisting>
|
|
<para>
|
|
Alternatively, you can provide your own implementation of the
|
|
<interfacename>MetadataStore</interfacename> interface (e.g. JdbcMetadataStore)
|
|
and configure it as a bean in the Application Context.
|
|
</para>
|
|
<para>
|
|
Starting with <emphasis>version 4.0</emphasis>, <classname>SimpleMetadataStore</classname>,
|
|
<classname>PropertiesPersistingMetadataStore</classname> and
|
|
<classname>RedisMetadataStore</classname> implement <interfacename>ConcurrentMetadataStore</interfacename>.
|
|
These provide for atomic updates and can be used across multiple component or application instances.
|
|
</para>
|
|
<section id="idempotent-receiver-pattern">
|
|
<title>Idempotent Receiver and Metadata Store</title>
|
|
<para>
|
|
The <emphasis>Metadata Store</emphasis> is useful for implementing the
|
|
EIP <ulink url="http://eaipatterns.com/IdempotentReceiver.html">Idempotent Receiver</ulink> pattern, when
|
|
there is need to <emphasis>filter</emphasis> an incoming Message if it has already been processed, and just discard
|
|
it or perform some other logic on discarding. The following configuration is an example of how to do this:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[<int:filter input-channel="serviceChannel"
|
|
output-channel="idempotentServiceChannel"
|
|
discard-channel="discardChannel"
|
|
expression="@metadataStore.get(headers.businessKey) == null"/>
|
|
|
|
<int:publish-subscribe-channel id="idempotentServiceChannel"/>
|
|
|
|
<int:outbound-channel-adapter channel="idempotentServiceChannel"
|
|
expression="@metadataStore.put(headers.businessKey, '')"/>
|
|
|
|
<int:service-activator input-channel="idempotentServiceChannel" ref="service"/>]]></programlisting>
|
|
<para>
|
|
The <code>value</code> of the idempotent entry may be some expiration date, after which that entry should
|
|
be removed from <emphasis>Metadata Store</emphasis> by some scheduled reaper.
|
|
</para>
|
|
<para>
|
|
Also see <xref linkend="idempotent-receiver"/>.
|
|
</para>
|
|
</section>
|
|
|
|
</section>
|