Files
spring-integration/src/reference/docbook/channel-adapter.xml

138 lines
8.2 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="channel-adapter"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Channel Adapter</title>
<para>
A Channel Adapter is a Message Endpoint that enables connecting a single sender or receiver to a Message Channel.
Spring Integration provides a number of adapters out of the box to support various transports, such as JMS, File,
HTTP, Web Services, Mail, and more. Those will be discussed in upcoming chapters of this reference guide. However, this
chapter focuses on the simple but flexible Method-invoking Channel Adapter support. There are both inbound and
outbound adapters, and each may be configured with XML elements provided in the core namespace. These provide an
easy way to extend Spring Integration as long as you have a method that can be invoked as either a source or
destination.
</para>
<section id="channel-adapter-namespace-inbound">
<title>Configuring An Inbound Channel Adapter</title>
<para>
An "inbound-channel-adapter" element can invoke any method on a Spring-managed Object and send a non-null return
value to a <interfacename>MessageChannel</interfacename> after converting it to a <classname>Message</classname>.
When the adapter's subscription is activated, a poller will attempt to receive messages from the source. The
poller will be scheduled with the <interfacename>TaskScheduler</interfacename> according to the provided
configuration. To configure the polling interval or cron expression for an individual channel-adapter,
provide a 'poller' element with one of the scheduling attributes, such as 'fixed-rate' or 'cron'.
<programlisting language="xml"><![CDATA[<int:inbound-channel-adapter ref="source1" method="method1" channel="channel1">
<int:poller fixed-rate="5000"/>
</int:inbound-channel-adapter>
<int:inbound-channel-adapter ref="source2" method="method2" channel="channel2">
<int:poller cron="30 * 9-17 * * MON-FRI"/>
</int:channel-adapter>]]></programlisting>
</para>
<note>
<para>
If no poller is provided, then a single default poller must be registered within the context.
See <xref linkend="endpoint-namespace"/> for more detail.
</para>
</note>
<important>
<para><emphasis>Poller Configuration</emphasis> </para>
<para>
Some <code>inbound-channel-adapter</code> types are backed by a <classname>SourcePollingChannelAdapter</classname> which
means they contain Poller configuration which will poll the <classname>MessageSource</classname> (invoke a custom method
which produces the value that becomes a <classname>Message</classname> payload) based on the configuration
specified in the Poller.
</para>
<para>
For example:
</para>
<programlisting language="xml"><![CDATA[<int:poller max-messages-per-poll="1" fixed-rate="1000"/>
<int:poller max-messages-per-poll="10" fixed-rate="1000"/>]]></programlisting>
<para>
In the the first configuration the polling task will be invoked once per poll and during such task (poll)
the method (which results in the production of the Message) will be invoked once based on the
<code>max-messages-per-poll</code> attribute value. In the second configuration the polling task will be invoked
10 times per poll or until it returns 'null' thus possibly producing 10 Messages per poll while each poll happens
at 1 second intervals.
However what if the configuration looks like this:
</para>
<programlisting language="xml"><![CDATA[<int:poller fixed-rate="1000"/>]]></programlisting>
<para>
Note there is no <code>max-messages-per-poll</code> specified. As you'll learn later the identical poller configuration
in the <classname>PollingConsumer</classname> (e.g., service-activator, filter, router etc.) would have a default
value of -1 for <code>max-messages-per-poll</code> which means "execute poling task non-stop unless polling method
returns null (e.g., no more Messages in the QueueChannel)" and then sleep for 1 second.
</para>
<para>
However in the SourcePollingChannelAdapter it is a bit different.
The default value for <code>max-messages-per-poll</code> will be set to 1 by default unless you explicitly set it to
a negative value (e.g., -1). It is done so to make sure that poller can react to a LifeCycle events (e.g., start/stop)
and prevent it from potentially spinning in the infinite loop if the implementation of the custom
method of the <classname>MessageSource</classname> has a potential to never return null and happened to be non-interruptible.
</para>
<para>
However if you are sure that your method can return null and you need the behavior where you want to poll
for as many sources as available per each poll, then you should explicitly set <code>max-messages-per-poll</code>
to negative value.
</para>
<programlisting language="xml"><![CDATA[<int:poller max-messages-per-poll="-1" fixed-rate="1000"/>]]></programlisting>
</important>
</section>
<section id="channel-adapter-namespace-outbound">
<title>Configuring Outbound Channel Adapter</title>
<para>
An "outbound-channel-adapter" element can also connect a <interfacename>MessageChannel</interfacename> to any POJO consumer
method that should be invoked with the payload of Messages sent to that channel.
<programlisting language="xml"><![CDATA[<int:outbound-channel-adapter channel="channel1" ref="target" method="handle"/>
<beans:bean id="target" class="org.Foo"/>]]>
</programlisting>
If the channel being adapted is a <interfacename>PollableChannel</interfacename>, provide a poller sub-element:
<programlisting language="xml"><![CDATA[<int:outbound-channel-adapter channel="channel2" ref="target" method="handle">
]]><emphasis><![CDATA[<int:poller fixed-rate="3000"/>
]]></emphasis><![CDATA[
</int:outbound-channel-adapter>
<beans:bean id="target" class="org.Foo"/>
]]></programlisting>
</para>
<para>
Using a "ref" attribute is generally recommended if the POJO consumer implementation can be reused
in other <code>&lt;outbound-channel-adapter&gt;</code> definitions. However if the consumer implementation
is only referenced by a single definition of the <code>&lt;outbound-channel-adapter&gt;</code>, you
can define it as inner bean:
<programlisting language="xml"><![CDATA[<int:outbound-channel-adapter channel="channel" method="handle">
<beans:bean class="org.Foo"/>
]]><![CDATA[
</int:outbound-channel-adapter>
]]></programlisting>
</para>
<note>
<para>
Using both the "ref" attribute and an inner handler definition in the same <code>&lt;outbound-channel-adapter&gt;</code>
configuration is not allowed as it creates an ambiguous condition. Such a configuration will result in an Exception
being thrown.
</para>
</note>
<para>
Any Channel Adapter can be created without a "channel" reference in which case it will implicitly create an
instance of <classname>DirectChannel</classname>. The created channel's name will match the "id" attribute
of the <code>&lt;inbound-channel-adapter&gt;</code> or <code>&lt;outbound-channel-adapter&gt;</code> element. Therefore, if the "channel"
is not provided, the "id" is required.
</para>
<para>
Like many other Spring Integration components, the <code>&lt;inbound-channel-adapter&gt;</code> and
<code>&lt;outbound-channel-adapter&gt;</code> also provide support for SpEL expression evaluation. To use SpEL, provide the
expression string via the 'expression' attribute instead of providing the 'ref' and 'method' attributes that are used for
method-invocation on a bean. When an Expression is evaluated, it follows the same contract as method-invocation where:
the <emphasis>expression</emphasis> for an <code>&lt;inbound-channel-adapter&gt;</code> will generate a message anytime the
evaluation result is a <emphasis>non-null</emphasis> value, while the <emphasis>expression</emphasis> for an
<code>&lt;outbound-channel-adapter&gt;</code> must be the equivalent of a <emphasis>void</emphasis> returning method invocation.
</para>
</section>
</section>