159 lines
7.2 KiB
XML
159 lines
7.2 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
|
<chapter id="splitter">
|
|
<title>Splitter</title>
|
|
|
|
<section id="splitter-annotation">
|
|
<title>Introduction</title>
|
|
|
|
<para>The Splitter is a component whose role is to partition a message in
|
|
several parts, and send the resulting messages to be processed
|
|
independently. Very often, they are upstream producers in a pipeline that
|
|
includes an Aggregator.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Programming model</title>
|
|
|
|
<para>The API for performing splitting consists from one base class,
|
|
AbstractMessageSplitter, which is a MessageHandler implementation,
|
|
encapsulating features which are common to splitters, such as filling in
|
|
the appropriate message headers CORRELATION_ID, SEQUENCE_SIZE, and
|
|
SEQUENCE_NUMBER on the messages that are produced. This allows to track
|
|
down the messages and the results of their processing (in a typical
|
|
scenario, these headers would be copied over to the messages that are
|
|
produced by the various transforming endpoints), and use them, for
|
|
example, in a Composed Message Processor scenario.</para>
|
|
|
|
<para>An excerpt from AbstractMessageSplitter can be seen below:</para>
|
|
|
|
<programlisting lang="java">public abstract class AbstractMessageSplitter
|
|
extends AbstractReplyProducingMessageConsumer {
|
|
...
|
|
protected abstract Object splitMessage(Message<?> message);
|
|
|
|
}</programlisting>
|
|
|
|
<para>For implementing a specific Splitter in an application, a developer
|
|
can extend AbstractMessageSplitter and implement the splitMessage method,
|
|
thus defining the actual logic for splitting the messages. The return
|
|
value can be one of the following:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>a Collection (or subclass thereof) or an array of Message
|
|
objects - in this case the messages will be sent as such (after the
|
|
CORRELATION_ID, SEQUENCE_SIZE and SEQUENCE_NUMBER are populated).
|
|
Using this approach gives more control to the developer, for example
|
|
for populating custom message headers as part of the splitting
|
|
process.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>a Collection (or subclass thereof) or an array of non-Message
|
|
objects - works like the prior case, except that each collection
|
|
element will be used as a Message payload. Using this approach allows
|
|
developers to focus on the domain objects without having to consider
|
|
the Messaging system and produces code that is easier to test.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>a Message or non-Message object (but not a Collection or an
|
|
Array) - it works like the previous cases, except that there is a
|
|
single message to be sent out.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>In Spring Integration, any POJO can implement the splitting
|
|
algorithm, provided that it defines a method that accepts a single
|
|
argument and has a return value. In this case, the return value of the
|
|
method will be interpreted as described above. The input argument might
|
|
either be a Message or a simple POJO. In the latter case, the splitter
|
|
will receive the payload of the incoming message. Since this decouples
|
|
the code from the Spring Integration API and will typically be easier
|
|
to test, it is the recommended approach.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Configuring a Splitter using XML</title>
|
|
|
|
<para>A splitter can be configured through XML as follows:<programlisting><channel id="inputChannel"/>
|
|
|
|
<splitter id="splitter" <co id="split1" />
|
|
ref="splitterBean" <co id="split2" />
|
|
method="split" <co id="split3" />
|
|
input-channel="inputChannel" <co id="split4" />
|
|
output-channel="outputChannel" <co id="split5" />/>
|
|
|
|
<channel id="outputChannel"/>
|
|
|
|
<beans:bean id="splitterBean" class="sample.PojoSplitter"/></programlisting><calloutlist>
|
|
<callout arearefs="split1">
|
|
<para>The id of the splitter is
|
|
<emphasis>optional</emphasis>.</para>
|
|
</callout>
|
|
|
|
<callout arearefs="split2">
|
|
<para>A reference to a bean defined in the application context. The
|
|
bean must implement the splitting logic as described in the section
|
|
above. <emphasis>Optional</emphasis>.
|
|
If reference to a bean is not provided, then it is assumed that the <emphasis>payload</emphasis> of the Message that arrived on the <code>input-channel</code> is
|
|
an implementation of <emphasis>java.util.Collection</emphasis> and the default splitting logic will be applied on such Collection,
|
|
incorporating each individual element into a Message and depositing it on the <code>output-channel</code>.
|
|
</para>
|
|
</callout>
|
|
|
|
<callout arearefs="split3">
|
|
<para>The method (defined on the bean specified above) that
|
|
implements the splitting logic.
|
|
<emphasis>Optional</emphasis>.</para>
|
|
</callout>
|
|
|
|
<callout arearefs="split4">
|
|
<para>The input channel of the splitter.
|
|
<emphasis>Required</emphasis>.</para>
|
|
</callout>
|
|
|
|
<callout arearefs="split5">
|
|
<para>The channel where the splitter will send the results of
|
|
splitting the incoming message. <emphasis>Optional (because incoming
|
|
messages can specify a reply channel themselves)</emphasis>.</para>
|
|
</callout>
|
|
</calloutlist></para>
|
|
<para>
|
|
Using a "ref" attribute is generally recommended if the custom splitter handler implementation can be reused in other
|
|
<code><splitter></code> definitions. However if the custom splitter handler implementation should be scoped to a
|
|
single definition of the <code><splitter></code>, you can configure an inner bean definition:
|
|
<programlisting language="xml"><![CDATA[<splitter id="testSplitter" input-channel="inChannel" method="split"
|
|
output-channel="outChannel">
|
|
<beans:bean class="org.foo.TestSplitter"/>
|
|
</spliter>]]></programlisting>
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Using both a "ref" attribute and an inner handler definition in the same <code><splitter></code>
|
|
configuration is not allowed, as it creates an ambiguous condition and will result in an Exception being thrown.
|
|
</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Configuring a Splitter with Annotations</title>
|
|
|
|
<para>The <interfacename>@Splitter</interfacename> annotation is
|
|
applicable to methods that expect either the
|
|
<interfacename>Message</interfacename> type or the message payload type,
|
|
and the return values of the method should be a collection of any type. If
|
|
the returned values are not actual <interfacename>Message</interfacename>
|
|
objects, then each of them will be sent as the payload of a message. Those
|
|
messages will be sent to the output channel as designated for the endpoint
|
|
on which the <interfacename>@Splitter</interfacename> is defined.
|
|
<programlisting language="java">@Splitter
|
|
List<LineItem> extractItems(Order order) {
|
|
return order.getItems()
|
|
}</programlisting></para>
|
|
</section>
|
|
|
|
</chapter>
|