Implicit channel declaration for items downstream of a `ChannelInterceptor` were not created. The `BPP` eagerly fetched the interceptors during its own creation; this caused the context initialization to fail because the channel initializer hasn't run yet. Defer creation of the interceptor beans until they are actually needed. Also, when using `@Configuration`, the channelInitializer is no longer the first bean in the bean factory. INT-3332 Use SmartLifeCycle to Apply Interceptors Instead of using a bean post processor, the interceptor processor now performs the channel interception when beans in phase Integer.MIN_VALUE are started - after all beans have been instantiated. Polishing
664 lines
38 KiB
XML
664 lines
38 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="redis"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
|
|
<title>Redis Support</title>
|
|
|
|
<para>
|
|
Since version 2.1 Spring Integration introduces support for <ulink url="http://redis.io/">Redis</ulink>:
|
|
<emphasis>"an open source advanced key-value store". </emphasis>
|
|
This support comes in the form of a Redis-based MessageStore as well as Publish-Subscribe Messaging adapters that
|
|
are supported by Redis via its <ulink url="http://redis.io/topics/pubsub">PUBLISH, SUBSCRIBE and UNSUBSCRIBE</ulink> commands.
|
|
</para>
|
|
|
|
<section id="redis-intro">
|
|
<title>Introduction</title>
|
|
<para>
|
|
To download, install and run Redis please refer to the <ulink url="http://redis.io/download">Redis documentation</ulink>.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="redis-connection">
|
|
<title>Connecting to Redis</title>
|
|
|
|
<para>To begin interacting with Redis you first need to connect to it. Spring Integration uses support provided by another Spring project,
|
|
<ulink url="https://github.com/SpringSource/spring-data-redis">Spring Data Redis</ulink>, which provides typical Spring constructs:
|
|
<classname>ConnectionFactory</classname> and <classname>Template</classname>. Those abstractions
|
|
simplify integration with several Redis-client Java APIs. Currently Spring-Data-Redis supports
|
|
<ulink url="https://github.com/xetorthio/jedis">jedis</ulink>, <ulink url="http://code.google.com/p/jredis/">jredis</ulink> and <ulink url="https://github.com/e-mzungu/rjc">rjc</ulink></para>
|
|
|
|
<para><emphasis>RedisConnectionFactory</emphasis> </para>
|
|
|
|
<para>
|
|
To connect to Redis you would use one of the implementations of the <classname>RedisConnectionFactory</classname> interface:
|
|
|
|
<programlisting language="java"><![CDATA[public interface RedisConnectionFactory extends PersistenceExceptionTranslator {
|
|
|
|
/**
|
|
* Provides a suitable connection for interacting with Redis.
|
|
*
|
|
* @return connection for interacting with Redis.
|
|
*/
|
|
RedisConnection getConnection();
|
|
}]]></programlisting>
|
|
</para>
|
|
|
|
<para>The example below shows how to create a <classname>JedisConnectionFactory</classname>.</para>
|
|
|
|
<para>In Java:
|
|
<programlisting language="java"><![CDATA[JedisConnectionFactory jcf = new JedisConnectionFactory();
|
|
jcf.afterPropertiesSet();]]></programlisting>
|
|
</para>
|
|
|
|
<para>Or in Spring's XML configuration:
|
|
<programlisting language="xml"><![CDATA[<bean id="redisConnectionFactory"
|
|
class="o.s.data.redis.connection.jedis.JedisConnectionFactory">
|
|
<property name="port" value="7379" />
|
|
</bean>]]></programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
The implementations of RedisConnectionFactory provide a set of properties such as port and host that can be set if needed.
|
|
Once an instance of RedisConnectionFactory is created, you can create an instance of RedisTemplate and inject it with the RedisConnectionFactory.
|
|
</para>
|
|
|
|
<para><emphasis>RedisTemplate</emphasis> </para>
|
|
|
|
<para>
|
|
As with other template classes in Spring (e.g., <classname>JdbcTemplate</classname>, <classname>JmsTemplate</classname>)
|
|
<classname>RedisTemplate</classname> is a helper class that simplifies Redis data access code.
|
|
For more information about <classname>RedisTemplate</classname> and its variations (e.g., <classname>StringRedisTemplate</classname>)
|
|
please refer to the <ulink url="http://static.springsource.org/spring-data/data-redis/docs/current/reference/">Spring-Data-Redis documentation</ulink>
|
|
</para>
|
|
|
|
<para>The code below shows how to create an instance of <classname>RedisTemplate</classname>:</para>
|
|
|
|
<para>In Java:
|
|
<programlisting language="java"><![CDATA[RedisTemplate rt = new RedisTemplate<String, Object>();
|
|
rt.setConnectionFactory(redisConnectionFactory);]]></programlisting>
|
|
</para>
|
|
|
|
<para>Or in Spring's XML configuration::
|
|
<programlisting language="xml"><![CDATA[<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
|
|
<property name="connectionFactory" ref="redisConnectionFactory"/>
|
|
</bean>]]></programlisting>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="redis-messages">
|
|
<title>Messaging with Redis</title>
|
|
|
|
<para>
|
|
As mentioned in the introduction Redis provides support for Publish-Subscribe messaging via its PUBLISH, SUBSCRIBE and UNSUBSCRIBE
|
|
commands. As with JMS and AMQP, Spring Integration provides Message Channels and adapters for sending and receiving messages via Redis.
|
|
</para>
|
|
|
|
<section id="redis-pub-sub-channel">
|
|
<title>Redis Publish/Subscribe channel</title>
|
|
|
|
<para>
|
|
Similar to the JMS there are cases where both the producer and consumer are intended to be part of the same application, running
|
|
within the same process. This could be accomplished by using a pair of inbound and outbound Channel Adapters,
|
|
however just like with Spring Integration's JMS support, there is a simpler approach to address this use case.
|
|
<programlisting language="xml"><![CDATA[<int-redis:publish-subscribe-channel id="redisChannel" topic-name="si.test.topic"/>]]></programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
The publish-subscribe-channel (above) will behave much like a normal <code><publish-subscribe-channel/></code> element from the
|
|
main Spring Integration namespace. It can be referenced by both <code>input-channel</code> and <code>output-channel</code> attributes of
|
|
any endpoint. The difference is that this channel is backed by a Redis topic name - a String value specified by the <code>topic-name</code>
|
|
attribute. However unlike JMS this topic doesn't have to be created in advance or even auto-created by Redis. In Redis topics are simple
|
|
String values that play the role of an address, and all the producer and consumer need to do to communicate is use the same String value
|
|
as their topic name. A simple subscription to this channel means that asynchronous pub-sub messaging is possible between the producing and
|
|
consuming endpoints, but unlike the asynchronous Message Channels created by adding a <code> <queue/></code> sub-element within
|
|
a simple Spring Integration <code><channel/></code> element, the Messages are not just stored in an in-memory queue. Instead those
|
|
Messages are passed through Redis allowing you to rely on its support for persistence and clustering as well as its interoperability with
|
|
other non-java platforms.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="redis-inbound-channel-adapter">
|
|
<title>Redis Inbound Channel Adapter</title>
|
|
<para>
|
|
The Redis-based Inbound Channel Adapter adapts incoming Redis messages into Spring Integration Messages in the same way as other
|
|
inbound adapters. It receives platform-specific messages (Redis in this case) and converts them to Spring Integration Messages using
|
|
a <classname>MessageConverter</classname> strategy.
|
|
|
|
<programlisting language="xml"><![CDATA[<int-redis:inbound-channel-adapter id="redisAdapter"
|
|
topics="foo, bar"
|
|
channel="receiveChannel"
|
|
error-channel="testErrorChannel"
|
|
message-converter="testConverter" />
|
|
|
|
<bean id="redisConnectionFactory"
|
|
class="o.s.data.redis.connection.jedis.JedisConnectionFactory">
|
|
<property name="port" value="7379" />
|
|
</bean>
|
|
|
|
<bean id="testConverter" class="foo.bar.SampleMessageConverter" />]]></programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
Above is a simple but complete configuration of a Redis Inbound Channel Adapter. Note that the above configuration relies on the
|
|
familiar Spring paradigm of auto-discovering certain beans. In this case the <code>redisConnectionFactory</code> is implicitly
|
|
injected into the adapter. You can of course specify it explicitly using the <code>connection-factory</code> attribute instead.
|
|
</para>
|
|
|
|
<para>
|
|
Also, note that the above configuration injects the adapter with a custom <code>MessageConverter</code>.
|
|
The approach is similar to JMS where <code>MessageConverters</code> are used to convert between
|
|
Redis Messages and the Spring Integration Message payloads. The default is a <code>SimpleMessageConverter</code>.
|
|
</para>
|
|
|
|
<para>
|
|
Inbound adapters can subscribe to multiple topic names hence the comma-delimited set of values in the
|
|
<code>topics</code> attribute.
|
|
</para>
|
|
<para>
|
|
Since <emphasis>Spring Integration 3.0</emphasis>, the Inbound Adapter, in addition to the existing <code>topics</code> attribute,
|
|
now has the <code>topic-patterns</code> attribute. This attribute contains a comma-delimited set of Redis topic patterns.
|
|
For more information regarding Redis publish/subscribe, see <ulink url="http://redis.io/topics/pubsub">Redis Pub/Sub</ulink>.
|
|
</para>
|
|
<para>
|
|
Inbound adapters can use a <classname>RedisSerializer</classname> to deserialize the body of Redis Messages.
|
|
The <code>serializer</code> attribute of the <code><int-redis:inbound-channel-adapter></code> can be set to an
|
|
empty string, which results in a <code>null</code> value for the <classname>RedisSerializer</classname> property.
|
|
In this case the raw <code>byte[]</code> bodies of Redis Messages are provided as the message payloads.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="redis-outbound-channel-adapter">
|
|
<title>Redis Outbound Channel Adapter</title>
|
|
<para>
|
|
The Redis-based Outbound Channel Adapter adapts outgoing Spring Integration messages into Redis messages in the same way as
|
|
other outbound adapters. It receives Spring Integration messages and converts them to platform-specific messages (Redis in this case)
|
|
using a <classname>MessageConverter</classname> strategy.
|
|
|
|
<programlisting language="xml"><![CDATA[<int-redis:outbound-channel-adapter id="outboundAdapter"
|
|
channel="sendChannel"
|
|
topic="foo"
|
|
message-converter="testConverter"/>
|
|
|
|
<bean id="redisConnectionFactory"
|
|
class="o.s.data.redis.connection.jedis.JedisConnectionFactory">
|
|
<property name="port" value="7379"/>
|
|
</bean>
|
|
|
|
<bean id="testConverter" class="foo.bar.SampleMessageConverter" />]]></programlisting>
|
|
</para>
|
|
<para>
|
|
As you can see the configuration is similar to the Redis Inbound Channel Adapter. The adapter is implicitly injected with
|
|
a <classname>RedisConnectionFactory</classname> which was defined with '<code>redisConnectionFactory</code>' as its bean name.
|
|
This example also includes the optional, custom <classname>MessageConverter</classname> (the '<code>testConverter</code>' bean).
|
|
</para>
|
|
<para>
|
|
Since <emphasis>Spring Integration 3.0</emphasis>, the <code><int-redis:outbound-channel-adapter></code>,
|
|
as an alternative to the <code>topic</code> attribute, has the <code>topic-expression</code> attribute to determine
|
|
the Redis topic against the Message at runtime. These attributes are mutually exclusive.
|
|
</para>
|
|
</section>
|
|
<section id="redis-queue-inbound-channel-adapter">
|
|
<title>Redis Queue Inbound Channel Adapter</title>
|
|
<para>
|
|
Since <emphasis>Spring Integration 3.0</emphasis>, a Queue Inbound Channel Adapter
|
|
is available to 'right pop' messages from a Redis List.
|
|
The adapter is message-driven using an internal listener thread and does not use a poller.
|
|
<programlisting language="xml"><![CDATA[<int-redis:queue-inbound-channel-adapter id="" ]]><co id="redis-m-d-c-a-id"/><![CDATA[
|
|
channel="" ]]><co id="redis-m-d-c-a-channel"/><![CDATA[
|
|
auto-startup="" ]]><co id="redis-m-d-c-a-autoStartup"/><![CDATA[
|
|
phase="" ]]><co id="redis-m-d-c-a-phase"/><![CDATA[
|
|
connection-factory="" ]]><co id="redis-m-d-c-a-connectionFactory"/><![CDATA[
|
|
queue="" ]]><co id="redis-m-d-c-a-queue"/><![CDATA[
|
|
error-channel="" ]]><co id="redis-m-d-c-a-errorChannel"/><![CDATA[
|
|
serializer="" ]]><co id="redis-m-d-c-a-serializer"/><![CDATA[
|
|
receive-timeout="" ]]><co id="redis-m-d-c-a-receiveTimeout"/><![CDATA[
|
|
recovery-interval="" ]]><co id="redis-m-d-c-a-recoveryInterval"/><![CDATA[
|
|
expect-message="" ]]><co id="redis-m-d-c-a-expectMessage"/><![CDATA[
|
|
task-executor=""/> ]]><co id="redis-m-d-c-a-task-executor"/>
|
|
</programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="redis-m-d-c-a-id">
|
|
<para>
|
|
The component bean name. If the <code>channel</code> attribute isn't provided a <classname>DirectChannel</classname>
|
|
is created and registered with application context with this <code>id</code> attribute as the bean name.
|
|
In this case, the endpoint itself is registered with the bean name <code>id + '.adapter'</code>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-channel">
|
|
<para>
|
|
The <interfacename>MessageChannel</interfacename> to which to send <interfacename>Message</interfacename>s from this Endpoint.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-autoStartup">
|
|
<para>
|
|
A <interfacename>SmartLifecycle</interfacename> attribute to specify whether this Endpoint should start automatically after
|
|
the application context start or not. Default is <code>true</code>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-phase">
|
|
<para>
|
|
A <interfacename>SmartLifecycle</interfacename> attribute to specify the <emphasis>phase</emphasis> in which
|
|
this Endpoint will be started. Default is <code>0</code>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-connectionFactory">
|
|
<para>
|
|
A reference to a <interfacename>RedisConnectionFactory</interfacename> bean. Defaults to
|
|
<code>redisConnectionFactory</code>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-queue">
|
|
<para>
|
|
The name of the Redis List on which the queue-based 'right pop' operation is performed to get Redis messages.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-errorChannel">
|
|
<para>
|
|
The <interfacename>MessageChannel</interfacename> to which to send <interfacename>ErrorMessage</interfacename>s with
|
|
<interfacename>Exception</interfacename>s from the listening task of the Endpoint. By default
|
|
the underlying <classname>MessagePublishingErrorHandler</classname> uses the
|
|
default <code>errorChannel</code> from the application context.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-serializer">
|
|
<para>
|
|
The <interfacename>RedisSerializer</interfacename> bean reference. Can be an empty string, which means 'no serializer'.
|
|
In this case the raw <code>byte[]</code> from the inbound Redis message is sent to the <code>channel</code> as the
|
|
<interfacename>Message</interfacename> payload. By default it is a <classname>JdkSerializationRedisSerializer</classname>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-receiveTimeout">
|
|
<para>
|
|
The timeout in milliseconds for 'right pop' operation to wait for a Redis message from the queue. Default is 1 second.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-recoveryInterval">
|
|
<para>
|
|
The time in milliseconds for which the listener task should sleep after exceptions on the 'right pop' operation,
|
|
before restarting the listener task.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-expectMessage">
|
|
<para>
|
|
Specify if this Endpoint expects data from the Redis queue to contain entire <interfacename>Message</interfacename>s.
|
|
If this attribute is set to <code>true</code>, the <code>serializer</code> can't be an empty string because messages
|
|
require some form of deserialization (JDK serialization by default).
|
|
Default is <code>false</code>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-task-executor">
|
|
<para>
|
|
A reference to a Spring <interfacename>TaskExecutor</interfacename> (or standard JDK 1.5+ <interfacename>Executor</interfacename>)
|
|
bean. It is used for the underlying listening task. By default a <classname>SimpleAsyncTaskExecutor</classname>
|
|
is used.
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</para>
|
|
</section>
|
|
<section id="redis-queue-outbound-channel-adapter">
|
|
<title>Redis Queue Outbound Channel Adapter</title>
|
|
<para>
|
|
Since <emphasis>Spring Integration 3.0</emphasis>, a Queue Outbound Channel Adapter
|
|
is available to 'left push' to a Redis List from Spring Integration messages:
|
|
<programlisting language="xml"><![CDATA[<int-redis:queue-outbound-channel-adapter id="" ]]><co id="redis-q-u-c-a-id"/><![CDATA[
|
|
channel="" ]]><co id="redis-q-u-c-a-channel"/><![CDATA[
|
|
connection-factory="" ]]><co id="redis-q-u-c-a-connectionFactory"/><![CDATA[
|
|
queue="" ]]><co id="redis-q-u-c-a-queue"/><![CDATA[
|
|
queue-expression="" ]]><co id="redis-q-u-c-a-queueExpression"/><![CDATA[
|
|
serializer="" ]]><co id="redis-q-u-c-a-serializer"/><![CDATA[
|
|
extract-payload="" />]]><co id="redis-q-u-c-a-extractPayload"/>
|
|
</programlisting>
|
|
<calloutlist>
|
|
<callout arearefs="redis-q-u-c-a-id">
|
|
<para>
|
|
The component bean name. If the <code>channel</code> attribute isn't provided, a <classname>DirectChannel</classname>
|
|
is created and registered with the application context with this <code>id</code> attribute as the bean name.
|
|
In this case, the endpoint is registered with the bean name <code>id + '.adapter'</code>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-q-u-c-a-channel">
|
|
<para>
|
|
The <interfacename>MessageChannel</interfacename> from which this Endpoint receives <interfacename>Message</interfacename>s.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-q-u-c-a-connectionFactory">
|
|
<para>
|
|
A reference to a <interfacename>RedisConnectionFactory</interfacename> bean. Defaults to
|
|
<code>redisConnectionFactory</code>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-q-u-c-a-queue">
|
|
<para>
|
|
The name of the Redis List on which the queue-based 'left push' operation is performed to send Redis messages.
|
|
This attribute is mutually exclusive with <code>queue-expression</code>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-q-u-c-a-queueExpression">
|
|
<para>
|
|
A SpEL <interfacename>Expression</interfacename> to determine the name of the Redis List
|
|
using the incoming <interfacename>Message</interfacename> at runtime as the <code>#root</code> variable.
|
|
This attribute is mutually exclusive with <code>queue</code>.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-m-d-c-a-serializer">
|
|
<para>
|
|
A <interfacename>RedisSerializer</interfacename> bean reference.
|
|
By default it is a <classname>JdkSerializationRedisSerializer</classname>.
|
|
However, for <classname>String</classname> payloads, a <classname>StringRedisSerializer</classname>
|
|
is used, if a <code>serializer</code> reference isn't provided.
|
|
</para>
|
|
</callout>
|
|
<callout arearefs="redis-q-u-c-a-extractPayload">
|
|
<para>
|
|
Specify if this Endpoint should send just the <emphasis>payload</emphasis> to the Redis queue,
|
|
or the entire <interfacename>Message</interfacename>.
|
|
Default is <code>true
|
|
</code>.
|
|
</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</para>
|
|
</section>
|
|
<section id="redis-application-events">
|
|
<title>Redis Application Events</title>
|
|
<para>
|
|
Since <emphasis>Spring Integration 3.0</emphasis>, the Redis module provides an implementation
|
|
of <classname>IntegrationEvent</classname> - which, in turn, is a
|
|
<interfacename>org.springframework.context.ApplicationEvent</interfacename>. The <classname>RedisExceptionEvent</classname>
|
|
encapsulates an <classname>Exception</classname>s from Redis operations (with the Endpoint being the <code>source</code>
|
|
of the event). For example, the <code><int-redis:queue-inbound-channel-adapter/></code>
|
|
emits those events after catching <classname>Exception</classname>s from the <code>BoundListOperations.rightPop</code>
|
|
operation.
|
|
The exception may be any generic <classname>org.springframework.data.redis.RedisSystemException</classname> or
|
|
a <classname>org.springframework.data.redis.RedisConnectionFailureException</classname>.
|
|
Handling these events using an <code><int-event:inbound-channel-adapter/></code> can be useful to determine
|
|
problems with background Redis tasks and to take administrative actions.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="redis-message-store">
|
|
<title>Redis Message Store</title>
|
|
|
|
<para>
|
|
As described in EIP, a <ulink url="http://www.eaipatterns.com/MessageStore.html">Message Store</ulink> allows you to persist Messages.
|
|
This can be very useful when dealing with components that have a capability to buffer messages
|
|
(<emphasis>Aggregator, Resequencer</emphasis>, etc.) if reliability is a concern.
|
|
In Spring Integration, the MessageStore strategy also provides the foundation for the
|
|
<ulink url="http://www.eaipatterns.com/StoreInLibrary.html">ClaimCheck</ulink> pattern, which is described in EIP as well.
|
|
</para>
|
|
|
|
<para>
|
|
Spring Integration's Redis module provides the <classname>RedisMessageStore</classname>.
|
|
</para>
|
|
|
|
<para>
|
|
<programlisting language="xml"><![CDATA[<bean id="redisMessageStore" class="o.s.i.redis.store.RedisMessageStore">
|
|
<constructor-arg ref="redisConnectionFactory"/>
|
|
</bean>
|
|
|
|
<int:aggregator input-channel="inputChannel" output-channel="outputChannel"
|
|
message-store="redisMessageStore"/>]]></programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
Above is a sample <classname>RedisMessageStore</classname> configuration that shows its usage by
|
|
an <emphasis>Aggregator</emphasis>. As you can see it is a simple bean configuration, and it expects a
|
|
<classname>RedisConnectionFactory</classname> as a constructor argument.
|
|
</para>
|
|
|
|
<para>By default the <classname>RedisMessageStore</classname> will use Java serialization to serialize the Message.
|
|
However if you want to use a different serialization technique (e.g., JSON), you can provide your own serializer via
|
|
the <code>valueSerializer</code> property of the <classname>RedisMessageStore</classname>.
|
|
</para>
|
|
<section id="redis-cms">
|
|
<title>Redis Channel Message Stores</title>
|
|
<para>
|
|
The <classname>RedisMessageStore</classname> above maintains each group as a value under a single key
|
|
(the group id). While this can be used to back a <classname>QueueChannel</classname> for persistence,
|
|
a specialized <classname>RedisChannelMessageStore</classname> is provided for that purpose (since
|
|
<emphasis>version 4.0</emphasis>). This store uses a <code>LIST</code> for each channel and
|
|
<code>LPUSH</code> when sending and <code>RPOP</code> when receiving messages. This store also
|
|
uses JDK serialization by default, but the value serializer can be modified as described above.
|
|
</para>
|
|
<para>
|
|
It is recommended that this store is used for backing channels, instead of the general
|
|
<classname>RedisMessageStore</classname>.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[<bean id="redisMessageStore" class="o.s.i.redis.store.RedisChannelMessageStore">
|
|
<constructor-arg ref="redisConnectionFactory"/>
|
|
</bean>
|
|
|
|
<int:channel id="somePersistentQueueChannel">
|
|
<int:queue message-store="redisMessageStore"/>
|
|
<int:channel>]]></programlisting>
|
|
<para>
|
|
The keys that are used to store the data have the form <code><storeBeanName>:<channelId></code>
|
|
(in the above example, <code>redisMessageStore:somePersistentQueueChannel</code>).
|
|
</para>
|
|
<para>
|
|
In addition, a subclass <classname>RedisChannelPriorityMessageStore</classname> is also provided.
|
|
When this is used with a <classname>QueueChannel</classname>, the messages are received in
|
|
(FIFO within) priority order. It uses the standard <classname
|
|
>IntegrationMessageHeaderAccessor.PRIORITY</classname> header and supports priority values
|
|
<code>0 - 9</code>; messages with other priorities (and messages with no priority) are retrieved
|
|
in FIFO order after any messages with priority.
|
|
</para>
|
|
<important>
|
|
These stores implement only <interfacename>BasicMessageGroupStore</interfacename> and
|
|
do not implement <interfacename>MessageGroupStore</interfacename>; they
|
|
can only be used for situations such as backing a <classname>QueueChannel</classname>.
|
|
</important>
|
|
</section>
|
|
</section>
|
|
<section id="redis-metadata-store">
|
|
<title>Redis Metadata Store</title>
|
|
<para>
|
|
As of <emphasis>Spring Integration 3.0</emphasis> a new Redis-based
|
|
<interfacename><ulink url="http://docs.spring.io/spring-integration/docs/latest-ga/api/org/springframework/integration/metadata/MetadataStore.html">MetadataStore</ulink></interfacename>
|
|
(<xref linkend="metadata-store"/>) implementation is available. The <classname>RedisMetadataStore</classname> can
|
|
be used to maintain state of a <interfacename>MetadataStore</interfacename>
|
|
across application restarts. This new <interfacename>MetadataStore</interfacename>
|
|
implementation can be used with adapters such as:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem><xref linkend="twitter-inbound"/></listitem>
|
|
<listitem><xref linkend="feed-inbound-channel-adapter"/></listitem>
|
|
<listitem><xref linkend="file-reading"/></listitem>
|
|
<listitem><xref linkend="ftp-inbound"/></listitem>
|
|
<listitem><xref linkend="sftp-inbound"/></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
In order to instruct these adapters to use the new <classname>RedisMetadataStore</classname>
|
|
simply declare a Spring bean using the bean name <emphasis role="bold">metadataStore</emphasis>.
|
|
The <emphasis>Twitter Inbound Channel Adapter</emphasis> and the
|
|
<emphasis>Feed Inbound Channel Adapter</emphasis> will both automatically
|
|
pick up and use the declared <classname>RedisMetadataStore</classname>.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[<bean name="metadataStore" class="o.s.i.redis.store.metadata.RedisMetadataStore">
|
|
<constructor-arg name="connectionFactory" ref="redisConnectionFactory"/>
|
|
</bean>]]></programlisting>
|
|
<para>
|
|
The <classname>RedisMetadataStore</classname> is backed by
|
|
<ulink url="http://docs.spring.io/spring-data/data-redis/docs/current/api/org/springframework/data/redis/support/collections/RedisProperties.html"
|
|
><classname>RedisProperties</classname></ulink> and interaction with it uses
|
|
<ulink url="http://docs.spring.io/spring-data/data-redis/docs/current/api/org/springframework/data/redis/core/BoundHashOperations.html"
|
|
><classname>BoundHashOperations</classname></ulink>, which, in turn, requires a <code>key</code> for the entire
|
|
<classname>Properties</classname> store. In the case of the <interfacename>MetadataStore</interfacename>, this
|
|
<code>key</code> plays the role of a <emphasis>region</emphasis>, which is useful in distributed environment,
|
|
when several applications use the same Redis server. By default this <code>key</code> has the value <code>MetaData</code>.
|
|
</para>
|
|
</section>
|
|
<section id="redis-store-inbound-channel-adapter">
|
|
<title>RedisStore Inbound Channel Adapter</title>
|
|
|
|
<para>
|
|
The <emphasis>RedisStore Inbound Channel Adapter</emphasis> is a polling consumer that reads data
|
|
from a Redis collection and sends it as a Message payload.
|
|
</para>
|
|
|
|
<programlisting language="xml"><![CDATA[<int-redis:store-inbound-channel-adapter id="listAdapter"
|
|
connection-factory="redisConnectionFactory"
|
|
key="myCollection"
|
|
channel="redisChannel"
|
|
collection-type="LIST" >
|
|
<int:poller fixed-rate="2000" max-messages-per-poll="10"/>
|
|
</int-redis:store-inbound-channel-adapter>]]></programlisting>
|
|
|
|
<para>
|
|
As you can see from the configuration above you configure a <emphasis>Redis Store Inbound Channel Adapter</emphasis> using
|
|
the <code>store-inbound-channel-adapter</code> element, providing values for various attributes such as:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem><code>key</code> or <code>key-expression</code> - The name of the key for the collection being used.</listitem>
|
|
<listitem><code>collection-type</code> - enumeration of the Collection types supported by this adapter. Supported Collections are: LIST, SET, ZSET, PROPERTIES, MAP</listitem>
|
|
<listitem><code>connection-factory</code> - reference to an instance of <classname>o.s.data.redis.connection.RedisConnectionFactory</classname></listitem>
|
|
<listitem><code>redis-template</code> - reference to an instance of <classname>o.s.data.redis.core.RedisTemplate</classname></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
and other attributes that are common across all other inbound adapters (e.g., 'channel').
|
|
</para>
|
|
<note>
|
|
You cannot set both <code>redis-template</code> and <code>connection-factory</code>.
|
|
</note>
|
|
<important>
|
|
By default, the adapter uses a <classname>StringRedisTemplate</classname>; this uses
|
|
<classname>StringRedisSerializer</classname>s for keys, values, hash keys and hash values. If your
|
|
Redis store contains objects that are serialized with other techniques, you must supply a
|
|
<classname>RedisTemplate</classname> configured with appropriate serializers.
|
|
For example, if the store is written to using a RedisStore Outbound Adapter that has its
|
|
<code>extract-payload-elements</code> set to false, you must provide a
|
|
<classname>RedisTemplate</classname> configured thus:
|
|
<programlisting language="xml"><![CDATA[<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
|
|
<property name="connectionFactory" ref="redisConnectionFactory"/>
|
|
<property name="keySerializer">
|
|
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
|
|
</property>
|
|
<property name="hashKeySerializer">
|
|
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
|
|
</property>
|
|
</bean>]]></programlisting>
|
|
<para>
|
|
This uses String serializers for keys and hash keys and the default JDK Serialization serializers for
|
|
values and hash values.
|
|
</para>
|
|
</important>
|
|
<para>
|
|
The example above is relatively simple and static since it has a literal value for the <code>key</code>.
|
|
Sometimes, you may need to change the value of the key at runtime based on some condition.
|
|
To do that, simply use <code>key-expression</code> instead, where the provided expression can be any valid SpEL expression.
|
|
</para>
|
|
<para>
|
|
Also, you may wish to perform some post-processing to the successfully processed data that was read from the Redis collection.
|
|
For example; you may want to move or remove the value after its been processed.
|
|
You can do this using the Transaction Synchronization feature that was added with Spring Integration 2.2.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[<int-redis:store-inbound-channel-adapter id="zsetAdapterWithSingleScoreAndSynchronization"
|
|
connection-factory="redisConnectionFactory"
|
|
key-expression="'presidents'"
|
|
channel="otherRedisChannel"
|
|
auto-startup="false"
|
|
collection-type="ZSET">
|
|
<int:poller fixed-rate="1000" max-messages-per-poll="2">
|
|
<int:transactional synchronization-factory="syncFactory"/>
|
|
</int:poller>
|
|
</int-redis:store-inbound-channel-adapter>
|
|
|
|
<int:transaction-synchronization-factory id="syncFactory">
|
|
<int:after-commit expression="payload.removeByScore(18, 18)"/>
|
|
</int:transaction-synchronization-factory>
|
|
|
|
<bean id="transactionManager" class="o.s.i.transaction.PseudoTransactionManager"/>]]></programlisting>
|
|
|
|
|
|
<para>
|
|
As you can see from the above all, you need to do is declare your poller to be transactional with a <code>transactional</code> element.
|
|
This element can reference a real transaction manager (for example if some other part of your flow invokes JDBC).
|
|
If you don't have a 'real' transaction, you can use a
|
|
<classname>o.s.i.transaction.PseudoTransactionManager</classname> which is an implementation
|
|
of Spring's <classname>PlatformTransactionManager</classname> and enables the use of the transaction synchronization
|
|
features of the redis adapter when there is no actual transaction.
|
|
</para>
|
|
<important>
|
|
This does NOT make the Redis activities themselves transactional, it simply allows the synchronization of actions to be taken before/after success (commit)
|
|
or after failure (rollback).
|
|
</important>
|
|
<para>
|
|
Once your poller is transactional all you need to do is set an instance of the
|
|
<classname>org.springframework.integration.transaction.TransactionSynchronizationFactory</classname> on the <code>transactional</code> element.
|
|
<classname>TransactionSynchronizationFactory</classname> will create an instance of the <classname>TransactionSynchronization</classname>.
|
|
For your convenience we've exposed a default SpEL-based <classname>TransactionSynchronizationFactory</classname> which allows
|
|
you to configure SpEL expressions, with their execution being coordinated (synchronized) with a transaction.
|
|
Expressions for before-commit, after-commit, and after-rollback are supported, together with a channel for each where the
|
|
evaluation result (if any) will be sent. For each sub-element you can specify <code>expression</code> and/or <code>channel</code>
|
|
attributes. If only the <code>channel</code> attribute is present the received Message will be sent there as part of the particular
|
|
synchronization scenario. If only the <code>expression</code> attribute is present and the result of an expression is a non-Null
|
|
value, a Message with the result as the payload will be generated and sent to a default channel (NullChannel) and will appear in the
|
|
logs (DEBUG). If you want the evaluation result to go to a specific channel add a <code>channel</code> attribute. If the result of an
|
|
expression is null or void, no Message will be generated.
|
|
</para>
|
|
<para>
|
|
For more information about transaction synchronization, see <xref linkend="transaction-synchronization"/>.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="redis-store-outbound-channel-adapter">
|
|
<title>RedisStore Outbound Channel Adapter</title>
|
|
|
|
<para>
|
|
The <emphasis>RedisStore Outbound Channel Adapter</emphasis> allows you to write a Message payload to a Redis collection
|
|
</para>
|
|
|
|
<programlisting language="xml"><![CDATA[<int-redis:store-outbound-channel-adapter id="redisListAdapter"
|
|
collection-type="LIST"
|
|
channel="requestChannel"
|
|
key="myCollection" />]]></programlisting>
|
|
|
|
<para>
|
|
As you can see from the configuration above, you configure a <emphasis>Redis Store Outbound Channel Adapter</emphasis> using
|
|
the <code>store-inbound-channel-adapter</code> element, providing values for various attributes such as:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem><code>key</code> or <code>key-expression</code> - The name of the key for the collection being used.</listitem>
|
|
<listitem><code>extract-payload-elements</code> - If set to <code>true</code> (Default) and the payload is an instance of a "multi-
|
|
value" object (i.e., Collection or Map) it will be stored using addAll/
|
|
putAll semantics. Otherwise, if set to <code>false</code> the payload will be stored
|
|
as a single entry regardless of its type. If the payload is not an instance
|
|
of a "multi-value" object, the value of this attribute is ignored and the
|
|
payload will always be stored as a single entry.</listitem>
|
|
<listitem><code>collection-type</code> - enumeration of the Collection types supported by this adapter. Supported Collections are: LIST, SET, ZSET, PROPERTIES, MAP</listitem>
|
|
<listitem><code>map-key-expression</code> - SpEL expression that returns the name of the key for entry being
|
|
stored. Only applies if the <code>collection-type</code> is MAP or PROPERTIES and
|
|
'extract-payload-elements' is false.</listitem>
|
|
<listitem><code>connection-factory</code> - reference to an instance of <classname>o.s.data.redis.connection.RedisConnectionFactory</classname></listitem>
|
|
<listitem><code>redis-template</code> - reference to an instance of <classname>o.s.data.redis.core.RedisTemplate</classname></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
and other attributes that are common across all other inbound adapters (e.g., 'channel').
|
|
</para>
|
|
<note>
|
|
You cannot set both <code>redis-template</code> and <code>connection-factory</code>.
|
|
</note>
|
|
|
|
<important>
|
|
By default, the adapter uses a <classname>StringRedisTemplate</classname>; this uses
|
|
<classname>StringRedisSerializer</classname>s for keys, values, hash keys and hash values. However, if
|
|
<code>extract-payload-elements</code> is set to false, a <classname>RedisTemplate</classname> using
|
|
<classname>StringRedisSerializer</classname>s for keys and hash keys, and
|
|
<classname>JdkSerializationRedisSerializer</classname>s for values and hash values will be used. With the JDK serializer, it is important
|
|
to understand that java serialization is used for all values, regardless of whether the value
|
|
is actually a collection or not. If you need more control over
|
|
the serialization of values, you may want to consider providing your own
|
|
<classname>RedisTemplate</classname> rather than relying upon these defaults.
|
|
</important>
|
|
<para>
|
|
The example above is relatively simple and static since it has a literal values for the <code>key</code> and other attributes.
|
|
Sometimes you may need to change the values dynamically at runtime based on some condition.
|
|
To do that simply use their <code>-expression</code> equivalents (<code>key-expression</code>, <code>map-key-expression</code> etc.) where
|
|
the provided expression can be any valid SpEL expression.
|
|
</para>
|
|
</section>
|
|
|
|
</chapter>
|