For reference see: https://jira.springsource.org/browse/INT-2882 * Verify spacing * Ensure all source code samples are typed: e.g. <programlisting language="xml"> * Ensure source code fits space in PDF format
671 lines
41 KiB
XML
671 lines
41 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="endpoint"
|
||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||
<title>Message Endpoints</title>
|
||
<para>
|
||
The first part of this chapter covers some background theory and reveals quite a bit about the underlying API
|
||
that drives Spring Integration's various messaging components. This information can be helpful if you want to
|
||
really understand what's going on behind the scenes. However, if you want to get up and running with the
|
||
simplified namespace-based configuration of the various elements, feel free to skip ahead to
|
||
<xref linkend="endpoint-namespace"/> for now.
|
||
</para>
|
||
<para>
|
||
As mentioned in the overview, Message Endpoints are responsible for connecting the various messaging components to
|
||
channels. Over the next several chapters, you will see a number of different components that consume Messages. Some
|
||
of these are also capable of sending reply Messages. Sending Messages is quite straightforward. As shown above in
|
||
<xref linkend="channel"/>, it's easy to <emphasis>send</emphasis> a Message to a Message Channel. However,
|
||
receiving is a bit more complicated. The main reason is that there are two types of consumers:
|
||
<ulink url="http://www.eaipatterns.com/PollingConsumer.html">Polling Consumers</ulink> and
|
||
<ulink url="http://www.eaipatterns.com/EventDrivenConsumer.html">Event Driven Consumers</ulink>.
|
||
</para>
|
||
<para>
|
||
Of the two, Event Driven Consumers are much simpler. Without any need to manage and schedule a separate poller
|
||
thread, they are essentially just listeners with a callback method. When connecting to one of Spring Integration's
|
||
subscribable Message Channels, this simple option works great. However, when connecting to a buffering, pollable
|
||
Message Channel, some component has to schedule and manage the polling thread(s). Spring Integration provides
|
||
two different endpoint implementations to accommodate these two types of consumers. Therefore, the consumers
|
||
themselves can simply implement the callback interface. When polling is required, the endpoint acts as a
|
||
<emphasis>container</emphasis> for the consumer instance. The benefit is similar to that of using a container for hosting
|
||
Message Driven Beans, but since these consumers are simply Spring-managed Objects running within an
|
||
ApplicationContext, it more closely resembles Spring's own MessageListener containers.
|
||
</para>
|
||
|
||
<section id="endpoint-handler">
|
||
<title>Message Handler</title>
|
||
<para>
|
||
Spring Integration's <interfacename>MessageHandler</interfacename> interface is implemented by many of the
|
||
components within the framework. In other words, this is not part of the public API, and a developer would not
|
||
typically implement <interfacename>MessageHandler</interfacename> directly. Nevertheless, it is used by a Message
|
||
Consumer for actually handling the consumed Messages, and so being aware of this strategy interface does help in
|
||
terms of understanding the overall role of a consumer. The interface is defined as follows:
|
||
<programlisting language="java">public interface MessageHandler {
|
||
|
||
void handleMessage(Message<?> message);
|
||
|
||
}</programlisting>
|
||
Despite its simplicity, this provides the foundation for most of the components that will be covered in the
|
||
following chapters (Routers, Transformers, Splitters, Aggregators, Service Activators, etc). Those components
|
||
each perform very different functionality with the Messages they handle, but the requirements for actually
|
||
receiving a Message are the same, and the choice between polling and event-driven behavior is also the same.
|
||
Spring Integration provides two endpoint implementations that <emphasis>host</emphasis> these callback-based handlers and allow
|
||
them to be connected to Message Channels.
|
||
</para>
|
||
</section>
|
||
|
||
<section id="endpoint-eventdrivenconsumer">
|
||
<title>Event Driven Consumer</title>
|
||
<para>
|
||
Because it is the simpler of the two, we will cover the Event Driven Consumer endpoint first. You may recall that
|
||
the <interfacename>SubscribableChannel</interfacename> interface provides a <methodname>subscribe()</methodname>
|
||
method and that the method accepts a <interfacename>MessageHandler</interfacename> parameter (as shown in
|
||
<xref linkend="channel-interfaces-subscribablechannel"/>):
|
||
<programlisting language="java">
|
||
subscribableChannel.subscribe(messageHandler);
|
||
</programlisting>
|
||
Since a handler that is subscribed to a channel does not have to actively poll that channel, this is an
|
||
Event Driven Consumer, and the implementation provided by Spring Integration accepts a
|
||
a <interfacename>SubscribableChannel</interfacename> and a <interfacename>MessageHandler</interfacename>:
|
||
<programlisting language="java">SubscribableChannel channel = context.getBean("subscribableChannel", SubscribableChannel.class);
|
||
|
||
EventDrivenConsumer consumer = new EventDrivenConsumer(channel, exampleHandler);</programlisting>
|
||
</para>
|
||
</section>
|
||
|
||
<section id="endpoint-pollingconsumer">
|
||
<title>Polling Consumer</title>
|
||
<para>
|
||
Spring Integration also provides a <classname>PollingConsumer</classname>, and it can be instantiated in
|
||
the same way except that the channel must implement <interfacename>PollableChannel</interfacename>:
|
||
</para>
|
||
<programlisting language="java">PollableChannel channel = context.getBean("pollableChannel", PollableChannel.class);
|
||
|
||
PollingConsumer consumer = new PollingConsumer(channel, exampleHandler);</programlisting>
|
||
|
||
<note>
|
||
For more information regarding Polling Consumers, please also read
|
||
<xref linkend="polling-consumer"/> as well as <xref linkend="channel-adapter"/>.
|
||
</note>
|
||
|
||
<para>
|
||
There are many other configuration options for the Polling Consumer. For example, the trigger is a required property:
|
||
</para>
|
||
<programlisting language="java">PollingConsumer consumer = new PollingConsumer(channel, handler);
|
||
|
||
consumer.setTrigger(new IntervalTrigger(30, TimeUnit.SECONDS));</programlisting>
|
||
<para>
|
||
Spring Integration currently provides two implementations of the <interfacename>Trigger</interfacename>
|
||
interface: <classname>IntervalTrigger</classname> and <classname>CronTrigger</classname>. The
|
||
<classname>IntervalTrigger</classname> is typically defined with a simple interval (in milliseconds), but
|
||
also supports an <emphasis>initialDelay</emphasis> property and a boolean <emphasis>fixedRate</emphasis> property (the default is false, i.e.
|
||
fixed delay):
|
||
</para>
|
||
<programlisting language="java">IntervalTrigger trigger = new IntervalTrigger(1000);
|
||
trigger.setInitialDelay(5000);
|
||
trigger.setFixedRate(true);</programlisting>
|
||
<para>
|
||
The <classname>CronTrigger</classname> simply requires a valid cron
|
||
expression (see the Javadoc for details):
|
||
</para>
|
||
<programlisting language="java">CronTrigger trigger = new CronTrigger("*/10 * * * * MON-FRI");</programlisting>
|
||
<para>
|
||
In addition to the trigger, several other polling-related configuration
|
||
properties may be specified:
|
||
</para>
|
||
<programlisting language="java">PollingConsumer consumer = new PollingConsumer(channel, handler);
|
||
|
||
consumer.setMaxMessagesPerPoll(10);
|
||
consumer.setReceiveTimeout(5000);</programlisting>
|
||
<para>
|
||
The <emphasis>maxMessagesPerPoll</emphasis> property specifies the maximum number of messages to receive within a given poll
|
||
operation. This means that the poller will continue calling receive() <emphasis>without waiting</emphasis>
|
||
until either <code>null</code> is returned or that max is reached. For example, if a poller has a 10 second
|
||
interval trigger and a <emphasis>maxMessagesPerPoll</emphasis> setting of 25, and it is polling a channel that has 100 messages
|
||
in its queue, all 100 messages can be retrieved within 40 seconds. It grabs 25, waits 10 seconds, grabs the
|
||
next 25, and so on.
|
||
</para>
|
||
<para>
|
||
The <emphasis>receiveTimeout</emphasis> property specifies the amount of time the poller should wait if no messages are
|
||
available when it invokes the receive operation. For example, consider two options that seem similar on
|
||
the surface but are actually quite different: the first has an interval trigger of 5 seconds and a receive
|
||
timeout of 50 milliseconds while the second has an interval trigger of 50 milliseconds and a receive timeout
|
||
of 5 seconds. The first one may receive a message up to 4950 milliseconds later than it arrived on the channel
|
||
(if that message arrived immediately after one of its poll calls returned). On the other hand, the second
|
||
configuration will never miss a message by more than 50 milliseconds. The difference is that the second
|
||
option requires a thread to wait, but as a result it is able to respond much more quickly to arriving messages.
|
||
This technique, known as <emphasis>long polling</emphasis>, can be used to emulate event-driven behavior on a polled source.
|
||
</para>
|
||
<para>
|
||
A Polling Consumer may also delegate to a Spring <interfacename>TaskExecutor</interfacename>,
|
||
as illustrated in the following example:
|
||
</para>
|
||
<programlisting language="java">PollingConsumer consumer = new PollingConsumer(channel, handler);
|
||
|
||
TaskExecutor taskExecutor = context.getBean("exampleExecutor", TaskExecutor.class);
|
||
consumer.setTaskExecutor(taskExecutor);</programlisting>
|
||
<para>
|
||
Furthermore, a <classname>PollingConsumer</classname> has a property called
|
||
<emphasis>adviceChain</emphasis>. This property allows you to specify a
|
||
<interfacename>List</interfacename> of AOP Advices for handling additional
|
||
cross cutting concerns including transactions. These advices are applied
|
||
around the <methodname>doPoll()</methodname> method. For more in-depth
|
||
information, please see the sections <emphasis>AOP Advice chains</emphasis>
|
||
and <emphasis>Transaction Support</emphasis> under <xref linkend="endpoint-namespace"/>.
|
||
</para>
|
||
<para>
|
||
The examples above show dependency lookups, but keep in mind that these
|
||
consumers will most often be configured as Spring <emphasis>bean definitions</emphasis>.
|
||
In fact, Spring Integration also provides a <interfacename>FactoryBean</interfacename>
|
||
called <classname>ConsumerEndpointFactoryBean</classname> that creates
|
||
the appropriate consumer type based on the type of channel, and there is
|
||
full XML namespace support to even further hide those details. The
|
||
namespace-based configuration will be featured as each component type is
|
||
introduced.
|
||
</para>
|
||
<note>
|
||
Many of the <interfacename>MessageHandler</interfacename> implementations are also capable of generating reply
|
||
Messages. As mentioned above, sending Messages is trivial when compared to the Message reception. Nevertheless,
|
||
<emphasis>when</emphasis> and <emphasis>how many</emphasis> reply Messages are sent depends on the handler
|
||
type. For example, an <emphasis>Aggregator</emphasis> waits for a number of Messages to arrive and is often
|
||
configured as a downstream consumer for a <emphasis>Splitter</emphasis> which may generate multiple
|
||
replies for each Message it handles. When using the namespace configuration, you do not strictly need to know
|
||
all of the details, but it still might be worth knowing that several of these components share a common base
|
||
class, the <classname>AbstractReplyProducingMessageHandler</classname>, and it provides a
|
||
<methodname>setOutputChannel(..)</methodname> method.
|
||
</note>
|
||
</section>
|
||
|
||
<section id="endpoint-namespace">
|
||
<title>Namespace Support</title>
|
||
<para>
|
||
Throughout the reference manual, you will see specific configuration examples for endpoint elements, such as
|
||
router, transformer, service-activator, and so on. Most of these will support an <emphasis>input-channel</emphasis> attribute and
|
||
many will support an <emphasis>output-channel</emphasis> attribute. After being parsed, these endpoint elements produce an instance
|
||
of either the <classname>PollingConsumer</classname> or the
|
||
<classname>EventDrivenConsumer</classname> depending on the type of the <emphasis>input-channel</emphasis> that is
|
||
referenced: <interfacename>PollableChannel</interfacename> or <interfacename>SubscribableChannel</interfacename>
|
||
respectively. When the channel is pollable, then the polling behavior is determined based on the endpoint
|
||
element's <emphasis>poller</emphasis> sub-element and its attributes.
|
||
</para>
|
||
|
||
<emphasis>Configuration</emphasis>
|
||
|
||
<para>Below you find a <emphasis>poller</emphasis> with all available configuration options:</para>
|
||
|
||
<programlisting language="xml"><![CDATA[<int:poller cron="" ]]><co id="poller-xml01-co" linkends="sp-gateway-xml01" /><![CDATA[
|
||
default="false" ]]><co id="poller-xml02-co" linkends="poller-xml02" /><![CDATA[
|
||
error-channel="" ]]><co id="poller-xml03-co" linkends="poller-xml03" /><![CDATA[
|
||
fixed-delay="" ]]><co id="poller-xml04-co" linkends="poller-xml04" /><![CDATA[
|
||
fixed-rate="" ]]><co id="poller-xml05-co" linkends="poller-xml05" /><![CDATA[
|
||
id="" ]]><co id="poller-xml06-co" linkends="poller-xml06" /><![CDATA[
|
||
max-messages-per-poll="" ]]><co id="poller-xml07-co" linkends="poller-xml07" /><![CDATA[
|
||
receive-timeout="" ]]><co id="poller-xml08-co" linkends="poller-xml08" /><![CDATA[
|
||
ref="" ]]><co id="poller-xml09-co" linkends="poller-xml09" /><![CDATA[
|
||
task-executor="" ]]><co id="poller-xml10-co" linkends="poller-xml10" /><![CDATA[
|
||
time-unit="MILLISECONDS" ]]><co id="poller-xml11-co" linkends="poller-xml11" /><![CDATA[
|
||
trigger=""> ]]><co id="poller-xml12-co" linkends="poller-xml12" /><![CDATA[
|
||
<int:advice-chain /> ]]><co id="poller-xml13-co" linkends="poller-xml13" /><![CDATA[
|
||
<int:transactional /> ]]><co id="poller-xml14-co" linkends="poller-xml14" /><![CDATA[
|
||
</int:poller>]]></programlisting>
|
||
|
||
<para>
|
||
<calloutlist>
|
||
<callout arearefs="poller-xml01-co" id="poller-xml01">
|
||
<para>
|
||
Provides the ability to configure Pollers using Cron expressions.
|
||
The underlying implementation uses a
|
||
<classname>org.springframework.scheduling.support.CronTrigger</classname>.
|
||
|
||
If this attribute is set, none of the following attributes
|
||
must be specified: <code>fixed-delay</code>, <code>trigger</code>,
|
||
<code>fixed-rate</code>, <code>ref</code>.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml02-co" id="poller-xml02">
|
||
<para>
|
||
By setting this attribute to <emphasis>true</emphasis>,
|
||
it is possible to define exactly one (1) global default
|
||
poller. An exception is raised if more than one default
|
||
poller is defined in the application context.
|
||
|
||
Any endpoints connected to a PollableChannel (PollingConsumer)
|
||
or any SourcePollingChannelAdapter that does not have any
|
||
explicitly configured poller will then use the global default
|
||
Poller.
|
||
<emphasis>Optional</emphasis>. Defaults to <code>false</code>.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml03-co" id="poller-xml03">
|
||
<para>
|
||
Identifies the channel which error messages will be sent to if
|
||
a failure occurs in this poller's invocation. To completely
|
||
suppress Exceptions, provide a reference to the
|
||
<code>nullChannel</code>. <emphasis>Optional</emphasis>.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml04-co" id="poller-xml04">
|
||
<para>
|
||
The fixed delay trigger uses a <classname>PeriodicTrigger</classname>
|
||
under the covers. If the <code>time-unit</code> attribute is
|
||
not used, the specified value is represented in milliseconds.
|
||
|
||
If this attribute is set, none of the following attributes
|
||
must be specified: <code>fixed-rate</code>, <code>trigger</code>,
|
||
<code>cron</code>, <code>ref</code>.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml05-co" id="poller-xml05">
|
||
<para>
|
||
The fixed rate trigger uses a <classname>PeriodicTrigger</classname>
|
||
under the covers. If the <code>time-unit</code> attribute is
|
||
not used the specified value is represented in milliseconds.
|
||
|
||
If this attribute is set, none of the following attributes
|
||
must be specified: <code>fixed-delay</code>, <code>trigger</code>,
|
||
<code>cron</code>, <code>ref</code>.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml06-co" id="poller-xml06">
|
||
<para>
|
||
The Id referring to the Poller's underlying bean-definition,
|
||
which is of type
|
||
<classname>org.springframework.integration.scheduling.PollerMetadata</classname>.
|
||
The <emphasis>id</emphasis> attribute is required for
|
||
a top-level poller element unless it is the default
|
||
poller (<code>default="true"</code>).
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml07-co" id="poller-xml07">
|
||
<para>
|
||
Please see <xref linkend="channel-adapter-namespace-inbound"/>
|
||
for more information. <emphasis>Optional</emphasis>. If
|
||
not specified the default values used depends on the context.
|
||
|
||
If a <classname>PollingConsumer</classname> is used, this atribute
|
||
will default to <emphasis>-1</emphasis>. However, if a
|
||
<classname>SourcePollingChannelAdapter</classname> is used,
|
||
then the <code>max-messages-per-poll</code> attribute defaults to
|
||
<emphasis>1</emphasis>.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml08-co" id="poller-xml08">
|
||
<para>
|
||
Value is set on the underlying class <classname>PollerMetadata</classname>
|
||
<emphasis>Optional</emphasis>. If not specified it defaults
|
||
to 1000 (milliseconds).
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml09-co" id="poller-xml09">
|
||
<para>
|
||
Bean reference to another top-level poller. The <code>ref</code>
|
||
attribute must not be present on the top-level <code>poller</code>
|
||
element.
|
||
|
||
However, if this attribute is set, none of the following attributes
|
||
must be specified: <code>fixed-rate</code>, <code>trigger</code>,
|
||
<code>cron</code>, <code>fixed-deleay</code>.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml10-co" id="poller-xml10">
|
||
<para>
|
||
Provides the ability to reference a custom <emphasis>task executor</emphasis>.
|
||
Please see the section below titled <emphasis>TaskExecutor Support</emphasis>
|
||
for further information. <emphasis>Optional</emphasis>.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml11-co" id="poller-xml11">
|
||
<para>
|
||
This attribute specifies the <classname>java.util.concurrent.TimeUnit</classname>
|
||
enum value on the underlying
|
||
<classname>org.springframework.scheduling.support.PeriodicTrigger</classname>.
|
||
Therefore, this attribute can <emphasis>ONLY</emphasis>
|
||
be used in combination with the <code>fixed-delay</code>
|
||
or <code>fixed-rate</code> attributes. If combined with
|
||
either <code>cron</code> or a <code>trigger</code> reference
|
||
attribute, it will cause a failure.
|
||
</para>
|
||
<para>
|
||
The minimal supported granularity for a
|
||
<classname>PeriodicTrigger</classname> is MILLISECONDS.
|
||
Therefore, the only available options are MILLISECONDS and
|
||
SECONDS. If this value is not provided, then any
|
||
<code>fixed-delay</code> or <code>fixed-rate</code> value
|
||
will be interpreted as MILLISECONDS by default.
|
||
</para>
|
||
<para>
|
||
Basically this enum provides a convenience for SECONDS-based
|
||
interval trigger values. For hourly, daily, and monthly
|
||
settings, consider using a <code>cron</code> trigger instead.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml12-co" id="poller-xml12">
|
||
<para>
|
||
Reference to any spring configured bean which implements
|
||
the <interfacename>org.springframework.scheduling.Trigger</interfacename>
|
||
interface.
|
||
<emphasis>Optional</emphasis>. However, if this attribute
|
||
is set, none of the following attributes must be specified:
|
||
<code>fixed-delay</code>, <code>fixed-rate</code>,
|
||
<code>cron</code>, <code>ref</code>.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml13-co" id="poller-xml13">
|
||
<para>
|
||
Allows to specify extra AOP Advices to handle additional
|
||
cross cutting concerns. Please see the section
|
||
below titled <emphasis>Transaction Support</emphasis>
|
||
for further information. <emphasis>Optional</emphasis>.
|
||
</para>
|
||
</callout>
|
||
<callout arearefs="poller-xml14-co" id="poller-xml14">
|
||
<para>
|
||
Pollers can be made transactional. Please see the section
|
||
below titled <emphasis>AOP Advice chains</emphasis>
|
||
for further information. <emphasis>Optional</emphasis>.
|
||
</para>
|
||
</callout>
|
||
</calloutlist>
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>Examples</emphasis>
|
||
</para>
|
||
|
||
<para>
|
||
For example, a simple interval-based poller with a 1-second interval would be
|
||
configured like this: <programlisting language="xml"><![CDATA[<int:transformer input-channel="pollable"
|
||
ref="transformer"
|
||
output-channel="output">
|
||
<int:poller fixed-rate="1000"/>
|
||
</int:transformer>]]></programlisting>
|
||
As an alternative to <emphasis>fixed-rate</emphasis> you can also use the <emphasis>fixed-delay</emphasis> attribute.
|
||
</para>
|
||
<para>
|
||
For a poller based on a Cron expression, use the <emphasis>cron</emphasis> attribute instead:
|
||
<programlisting language="xml"><![CDATA[<int:transformer input-channel="pollable"
|
||
ref="transformer"
|
||
output-channel="output">
|
||
<int:poller cron="*/10 * * * * MON-FRI"/>
|
||
</int:transformer>]]></programlisting>
|
||
</para>
|
||
<para>
|
||
If the input channel is a <interfacename>PollableChannel</interfacename>, then the poller configuration is
|
||
required. Specifically, as mentioned above, the <emphasis>trigger</emphasis> is a required property of the PollingConsumer class.
|
||
Therefore, if you omit the <emphasis>poller</emphasis> sub-element for a Polling Consumer endpoint's configuration, an Exception
|
||
may be thrown. The exception will also be thrown if you attempt to configure a poller on the element that is
|
||
connected to a non-pollable channel.
|
||
</para>
|
||
<para>
|
||
It is also possible to create top-level pollers in which case only a <emphasis>ref</emphasis> is required:
|
||
</para>
|
||
|
||
<programlisting language="xml"><![CDATA[<int:poller id="weekdayPoller" cron="*/10 * * * * MON-FRI"/>
|
||
|
||
<int:transformer input-channel="pollable"
|
||
ref="transformer"
|
||
output-channel="output">
|
||
<int:poller ref="weekdayPoller"/>
|
||
</int:transformer>]]></programlisting>
|
||
|
||
<note>
|
||
<para>
|
||
The <emphasis>ref</emphasis> attribute is only allowed on the inner-poller definitions. Defining this attribute on a top-level
|
||
poller will result in a configuration exception thrown during initialization of the Application Context.
|
||
</para>
|
||
</note>
|
||
|
||
<para>
|
||
<emphasis>Global Default Pollers</emphasis>
|
||
</para>
|
||
|
||
<para>
|
||
In fact, to simplify the configuration even further, you can define a global default poller. A single top-level poller within
|
||
an ApplicationContext may have the <code>default</code> attribute with a value of <emphasis>true</emphasis>. In that case, any
|
||
endpoint with a PollableChannel for its input-channel that is defined within the same ApplicationContext and has
|
||
no explicitly configured <emphasis>poller</emphasis> sub-element will use that default.
|
||
</para>
|
||
<programlisting language="xml"><![CDATA[<int:poller id="defaultPoller" default="true" max-messages-per-poll="5" fixed-rate="3000"/>
|
||
|
||
<!-- No <poller/> sub-element is necessary since there is a default -->
|
||
<int:transformer input-channel="pollable"
|
||
ref="transformer"
|
||
output-channel="output"/>]]></programlisting>
|
||
|
||
<para>
|
||
<emphasis>Transaction Support</emphasis>
|
||
</para>
|
||
|
||
<para>
|
||
Spring Integration also provides transaction support for the pollers so that each receive-and-forward
|
||
operation can be performed as an atomic unit-of-work. To configure transactions for a poller, simply add the
|
||
<emphasis><transactional/></emphasis> sub-element. The attributes for this element should be familiar to anyone who has
|
||
experience with Spring's Transaction management:
|
||
</para>
|
||
|
||
<programlisting language="xml"><![CDATA[<int:poller fixed-delay="1000">
|
||
<int:transactional transaction-manager="txManager"
|
||
propagation="REQUIRED"
|
||
isolation="REPEATABLE_READ"
|
||
timeout="10000"
|
||
read-only="false"/>
|
||
</int:poller>]]></programlisting>
|
||
|
||
<para>
|
||
For more information please refer to <xref linkend="transaction-poller"/>.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>AOP Advice chains</emphasis>
|
||
</para>
|
||
|
||
<para>
|
||
Since Spring transaction support depends on the Proxy mechanism with <classname>TransactionInterceptor</classname> (AOP Advice) handling transactional
|
||
behavior of the message flow initiated by the poller, some times there is a need to provide extra Advice(s) to handle other
|
||
cross cutting behavior associated with the poller. For that poller defines an <emphasis>advice-chain</emphasis> element allowing you to add
|
||
more advices - class that implements <classname>MethodInterceptor</classname> interface..
|
||
<programlisting language="xml"><![CDATA[<int:service-activator id="advicedSa" input-channel="goodInputWithAdvice" ref="testBean"
|
||
method="good" output-channel="output">
|
||
<int:poller max-messages-per-poll="1" fixed-rate="10000">
|
||
<int:transactional transaction-manager="txManager" />
|
||
<int:advice-chain>
|
||
<ref bean="adviceA" />
|
||
<beans:bean class="org.bar.SampleAdvice"/>
|
||
</int:advice-chain>
|
||
</int:poller>
|
||
</int:service-activator>]]></programlisting>
|
||
For more information on how to implement MethodInterceptor please refer to AOP sections of Spring
|
||
reference manual (section 8 and 9). Advice chain can also be applied on the poller that does not have
|
||
any transaction configuration essentially allowing you to enhance the behavior of the message flow initiated by the poller.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>TaskExecutor Support</emphasis>
|
||
</para>
|
||
|
||
<para>
|
||
The polling threads may be executed by any instance of Spring's <interfacename>TaskExecutor</interfacename>
|
||
abstraction. This enables concurrency for an endpoint or group of endpoints. As of Spring 3.0, there is a <emphasis>task</emphasis>
|
||
namespace in the core Spring Framework, and its <executor/> element supports the creation of a simple thread
|
||
pool executor. That element accepts attributes for common concurrency settings such as pool-size and queue-capacity.
|
||
Configuring a thread-pooling executor can make a substantial difference in how the endpoint performs under load. These
|
||
settings are available per-endpoint since the performance of an endpoint is one of the major factors to consider
|
||
(the other major factor being the expected volume on the channel to which the endpoint subscribes). To enable
|
||
concurrency for a polling endpoint that is configured with the XML namespace support, provide the <emphasis>task-executor</emphasis>
|
||
reference on its <poller/> element and then provide one or more of the properties shown below:
|
||
<programlisting language="xml"><![CDATA[<int:poller task-executor="pool" fixed-rate="1000"/>
|
||
|
||
<task:executor id="pool"
|
||
pool-size="5-25"
|
||
queue-capacity="20"
|
||
keep-alive="120"/>]]></programlisting>
|
||
If no <emphasis>task-executor</emphasis> is provided, the consumer's handler will be invoked in the caller's thread. Note that the
|
||
<emphasis>caller</emphasis> is usually the default <interfacename>TaskScheduler</interfacename>
|
||
(see <xref linkend="namespace-taskscheduler"/>). Also, keep in mind that the <emphasis>task-executor</emphasis> attribute can
|
||
provide a reference to any implementation of Spring's <interfacename>TaskExecutor</interfacename> interface by
|
||
specifying the bean name. The <emphasis>executor</emphasis> element above is simply provided for convenience.
|
||
</para>
|
||
<para>
|
||
As mentioned in the background section for Polling Consumers above, you can also configure a Polling Consumer
|
||
in such a way as to emulate event-driven behavior. With a long receive-timeout and a short interval-trigger,
|
||
you can ensure a very timely reaction to arriving messages even on a polled message source. Note that this
|
||
will only apply to sources that have a blocking wait call with a timeout. For example, the File poller does
|
||
not block, each receive() call returns immediately and either contains new files or not. Therefore, even if
|
||
a poller contains a long receive-timeout, that value would never be usable in such a scenario. On the other
|
||
hand when using Spring Integration's own queue-based channels, the timeout value does have a chance to
|
||
participate. The following example demonstrates how a Polling Consumer will receive Messages nearly
|
||
instantaneously.
|
||
<programlisting language="xml"><![CDATA[<int:service-activator input-channel="someQueueChannel"
|
||
output-channel="output">
|
||
<int:poller receive-timeout="30000" fixed-rate="10"/>
|
||
|
||
</int:service-activator>]]></programlisting>
|
||
Using this approach does not carry much overhead since internally it is nothing more then a timed-wait thread
|
||
which does not require nearly as much CPU resource usage as a thrashing, infinite while loop for example.
|
||
</para>
|
||
</section>
|
||
|
||
<section id="polling-consumer-change-polling-rate">
|
||
<title>Change Polling Rate at Runtime</title>
|
||
<para>
|
||
When configuring Pollers with a <code>fixed-delay</code> or
|
||
<code>fixed-rate</code> attribute, the default implementation will use
|
||
a <classname>PeriodicTrigger</classname> instance. The
|
||
<classname>PeriodicTrigger</classname> is part of the Core Spring Framework
|
||
and it accepts the <emphasis>interval</emphasis> as a constructor
|
||
argument, only. Therefore it cannot be changed at runtime.
|
||
</para>
|
||
<para>
|
||
However, you can define your own implementation of the
|
||
<interfacename>org.springframework.scheduling.Trigger</interfacename>
|
||
interface. You could even use the PeriodicTrigger as a starting point.
|
||
Then, you can add a setter for the interval (period), or you could even
|
||
embed your own throttling logic within the trigger itself if desired.
|
||
The <emphasis>period</emphasis> property will be used with each call to
|
||
<emphasis>nextExecutionTime</emphasis> to schedule the next poll.
|
||
|
||
To use this custom trigger within pollers, declare the bean defintion of
|
||
the custom Trigger in your application context and inject the dependency
|
||
into your Poller configuration using the <code>trigger</code> attribute,
|
||
which references the custom Trigger bean instance.
|
||
|
||
You can now obtain a reference to the Trigger bean and the polling
|
||
interval can be changed between polls.
|
||
</para>
|
||
<para>
|
||
For an example, please see the Spring Integration Samples
|
||
project. It contains a sample called <emphasis>dynamic-poller</emphasis>,
|
||
which uses a custom Trigger and demonstrates the ability to change the polling
|
||
interval at runtime.
|
||
</para>
|
||
<itemizedlist>
|
||
<listitem><ulink url="https://github.com/SpringSource/spring-integration-samples/tree/master/intermediate">
|
||
https://github.com/SpringSource/spring-integration-samples/tree/master/intermediate
|
||
</ulink></listitem>
|
||
</itemizedlist>
|
||
<para>
|
||
The sample provides a custom Trigger which implements the
|
||
<emphasis><ulink url="http://static.springsource.org/spring/docs/current/javadoc-api/org/springframework/scheduling/Trigger.html">org.springframework.scheduling.Trigger</ulink></emphasis>
|
||
interface. The sample's Trigger is based on Spring's <ulink url="http://static.springsource.org/spring/docs/current/javadoc-api/org/springframework/scheduling/support/PeriodicTrigger.html">PeriodicTrigger</ulink>
|
||
implementation. However, the fields of the custom trigger are not final
|
||
and the properties have explicit getters and setters, allowing to dynamically
|
||
change the polling period at runtime.
|
||
</para>
|
||
<note><para>
|
||
It is important to note, though, that because the Trigger method is
|
||
<emphasis>nextExecutionTime()</emphasis>, any changes to a dynamic trigger
|
||
will not take effect until the next poll, based on the existing configuration.
|
||
It is not possible to force a trigger to fire before it's currently
|
||
configured next execution time.
|
||
</para></note>
|
||
</section>
|
||
|
||
<section id="payload-type-conversion">
|
||
<title>Payload Type Conversion</title>
|
||
<para>
|
||
Throughout the reference manual, you will also see specific configuration and implementation examples of various endpoints
|
||
which can accept a Message or any arbitrary Object as an input parameter. In the case of an Object, such a parameter will
|
||
be mapped to a Message payload or part of the payload or header (when using the Spring Expression Language). However there
|
||
are times when the type of input parameter of the endpoint method does not match the type of the payload or its part.
|
||
In this scenario we need to perform type conversion. Spring Integration provides a convenient way for registering type
|
||
converters (using the Spring 3.x ConversionService) within its own instance of a conversion service bean named
|
||
<emphasis>integrationConversionService</emphasis>.
|
||
That bean is automatically created as soon as the first converter is defined using the Spring Integration namespace support.
|
||
|
||
To register a Converter all you need is to implement
|
||
<interfacename>org.springframework.core.convert.converter.Converter</interfacename> and define it via
|
||
convenient namespace support:
|
||
<programlisting language="xml"><![CDATA[<int:converter ref="sampleConverter"/>
|
||
|
||
<bean id="sampleConverter" class="foo.bar.TestConverter"/>]]></programlisting>
|
||
|
||
or as an inner bean:
|
||
<programlisting language="xml"><![CDATA[<int:converter>
|
||
<bean class="o.s.i.config.xml.ConverterParserTests$TestConverter3"/>
|
||
</int:converter>]]></programlisting>
|
||
</para>
|
||
<important>
|
||
<para>
|
||
When configuring an <emphasis>Application Context</emphasis>, the
|
||
Spring Framework allows you to add a <emphasis>conversionService</emphasis> bean
|
||
(see <ulink url="http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html#core-convert-Spring-config">
|
||
Configuring a ConversionService</ulink> chapter). This service is used, when needed,
|
||
to perform appropriate conversions during bean creation and configuration.
|
||
</para>
|
||
<para>
|
||
In contrast, the <emphasis>integrationConversionService</emphasis> is used for runtime conversions.
|
||
These uses are quite different; converters that are intended for use when wiring bean
|
||
constructor-args and properties may produce unintended results if used at runtime
|
||
for Spring Integration expression evaluation against
|
||
Messages within Datatype Channels, Payload Type transformers etc.
|
||
</para>
|
||
<para>
|
||
However, if you do want to use the Spring <emphasis>conversionService</emphasis> as
|
||
the Spring Integration <emphasis>integrationConversionService</emphasis>,
|
||
you can configure an <emphasis>alias</emphasis> in the Application Context:
|
||
<programlisting language="xml"><![CDATA[<alias name="conversionService" alias="integrationConversionService"/>]]></programlisting>
|
||
In this case the <emphasis>conversionService</emphasis>'s Converters will be available for Spring Integration
|
||
runtime conversion.
|
||
</para>
|
||
</important>
|
||
|
||
</section>
|
||
|
||
<section id="async-polling">
|
||
<title>Asynchronous polling</title>
|
||
<para>
|
||
If you want the polling to be asynchronous, a Poller can optionally specify a <emphasis>task-executor</emphasis> attribute
|
||
pointing to an existing instance of any <classname>TaskExecutor</classname> bean
|
||
(Spring 3.0 provides a convenient namespace configuration via the <code>task</code> namespace). However, there are certain things
|
||
you must understand when configuring a Poller with a TaskExecutor.
|
||
</para>
|
||
<para>
|
||
The problem is that there are two configurations in place. The <emphasis>Poller</emphasis> and the <emphasis>TaskExecutor</emphasis>,
|
||
and they both have to be in tune with each other otherwise you might end up creating an artificial memory leak.
|
||
</para>
|
||
<para>
|
||
Let's look at the following configuration provided by one of the users on the Spring Integration
|
||
forum (http://forum.springsource.org/showthread.php?t=94519):
|
||
|
||
<programlisting language="xml"><![CDATA[<int:service-activator input-channel="publishChannel" ref="myService">
|
||
<int:poller receive-timeout="5000" task-executor="taskExecutor" fixed-rate="50"/>
|
||
</int:service-activator>
|
||
|
||
<task:executor id="taskExecutor" pool-size="20" queue-capacity="20"/>]]></programlisting>
|
||
|
||
The above configuration demonstrates one of those out of tune configurations.
|
||
</para>
|
||
<para>
|
||
The poller keeps scheduling new tasks even though all the threads are blocked waiting for either a new message to arrive,
|
||
or the timeout to expire. Given that there are 20 threads executing tasks with a 5 second timeout, they will be executed
|
||
at a rate of 4 per second (5000/20 = 250ms). But, new tasks are being scheduled at a rate of 20 per second, so the internal
|
||
queue in the task executor will grow at a rate of 16 per second (while the process is idle), so we essentially have a memory leak.
|
||
</para>
|
||
<para>
|
||
One of the ways to handle this is to set the <code>queue-capacity</code> attribute of the Task Executor to 0. You can also
|
||
manage it by specifying what to do with messages that can not be queued by setting the <code>rejection-policy</code> attribute
|
||
of the Task Executor (e.g., DISCARD). In other words there are certain details you must understand with regard to configuring
|
||
the TaskExecutor. Please refer to - <emphasis>Section 25 - Task Execution and Scheduling</emphasis> of the Spring reference manual
|
||
for more detail on the subject.
|
||
</para>
|
||
</section>
|
||
</section>
|