553 lines
34 KiB
XML
553 lines
34 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
|
<chapter id="config">
|
|
<title>Configuration</title>
|
|
|
|
<section id="config-intro">
|
|
<title>Introduction</title>
|
|
<para>
|
|
Spring Integration offers a number of configuration options. Which option you choose depends upon your particular
|
|
needs and at what level you prefer to work. As with the Spring framework in general, it is also possible to mix
|
|
and match the various techniques according to the particular problem at hand. For example, you may choose the
|
|
XSD-based namespace for the majority of configuration combined with a handful of objects that are configured with
|
|
annotations. As much as possible, the two provide consistent naming. XML elements defined by the XSD schema will
|
|
match the names of annotations, and the attributes of those XML elements will match the names of annotation
|
|
properties. Direct usage of the API is yet another option and is described in detail in <xref linkend="api"/>.
|
|
We expect that most users will choose one of the higher-level options, such as the namespace-based or
|
|
annotation-driven configuration.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="namespace">
|
|
<title>Namespace Support</title>
|
|
<para>
|
|
Spring Integration components can be configured with XML elements that map directly to the terminology and
|
|
concepts of enterprise integration. In many cases, the element names match those of the
|
|
<ulink url="http://www.eaipatterns.com">Enterprise Integration Patterns</ulink>.
|
|
</para>
|
|
<para>
|
|
To enable Spring Integration's namespace support within your Spring configuration files, add the following
|
|
namespace reference and schema mapping in your top-level 'beans' element:
|
|
<programlisting language="xml"><![CDATA[<beans xmlns="http://www.springframework.org/schema/beans"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
]]><emphasis>xmlns:integration="http://www.springframework.org/schema/integration"</emphasis><![CDATA[
|
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
|
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
]]><emphasis>http://www.springframework.org/schema/integration
|
|
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd"</emphasis>></programlisting>
|
|
</para>
|
|
<para>
|
|
You can choose any name after "xmlns:"; <emphasis>integration</emphasis> is used here for clarity, but you might
|
|
prefer a shorter abbreviation. Of course if you are using an XML-editor or IDE support, then the availability of
|
|
auto-completion may convince you to keep the longer name for clarity. Alternatively, you can create configuration
|
|
files that use the Spring Integration schema as the primary namespace:
|
|
<programlisting language="xml"><emphasis><beans:beans xmlns="http://www.springframework.org/schema/integration"</emphasis><![CDATA[
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
]]><emphasis>xmlns:beans="http://www.springframework.org/schema/beans"</emphasis><![CDATA[
|
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
|
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
http://www.springframework.org/schema/integration
|
|
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd">]]></programlisting>
|
|
</para>
|
|
<para>
|
|
When using this alternative, no prefix is necessary for the Spring Integration elements. On the other hand, if
|
|
you want to define a generic Spring "bean" within the same configuration file, then a prefix would be required
|
|
for the bean element (<beans:bean ... />). Since it is generally a good idea to modularize the
|
|
configuration files themselves based on responsibility and/or architectural layer, you may find it appropriate to
|
|
use the latter approach in the integration-focused configuration files, since generic beans are seldom necessary
|
|
within those same files. For purposes of this documentation, we will assume the "integration" namespace is
|
|
primary.
|
|
</para>
|
|
|
|
<section id="namespace-channel">
|
|
<title>Configuring Message Channels</title>
|
|
<para>
|
|
To create a Message Channel instance, you can use the generic 'channel' element:
|
|
<programlisting language="xml"><channel id="exampleChannel"/></programlisting>
|
|
</para>
|
|
<para>
|
|
The default channel type is <emphasis>Point to Point</emphasis>. To create a
|
|
<emphasis>Publish Subscribe</emphasis> channel, provide a value of <emphasis>true</emphasis> for the
|
|
'publish-subscribe' attribute of the channel element:
|
|
<programlisting language="xml"><channel id="exampleChannel" publish-subscribe="true"/></programlisting>
|
|
</para>
|
|
<para>
|
|
When the <classname>MessageBus</classname> detects and registers channels, it will establish a dispatcher for
|
|
each channel. The default dispatcher settings were previously displayed in
|
|
<xref linkend="api-messagebus-dispatcherpolicy"/>. To customize these settings for a particular channel, add
|
|
the 'dispatcher-policy' sub-element and provide one or more of the attributes shown below:
|
|
<programlisting language="xml"><![CDATA[<channel id="exampleChannel" publish-subscribe="true">
|
|
<dispatcher-policy max-messages-per-task="25"
|
|
receive-timeout="10"
|
|
rejection-limit="3"
|
|
retry-interval="500"
|
|
should-fail-on-rejection-limit="false"/>
|
|
</channel>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
To create a <ulink url="http://www.eaipatterns.com/DatatypeChannel.html">Datatype Channel</ulink> that only
|
|
accepts messages containing a certain payload type, provide the fully-qualified class name in the
|
|
channel element's <literal>datatype</literal> attribute:
|
|
<programlisting language="xml"><![CDATA[<channel id="numberChannel" datatype="java.lang.Number"/>]]></programlisting>
|
|
Note that the type check passes for any type that is <emphasis>assignable</emphasis> to the channel's
|
|
datatype. In other words, the "numberChannel" above would accept messages whose payload is
|
|
<classname>java.lang.Integer</classname> or <classname>java.lang.Double</classname>. Multiple types can be
|
|
provided as a comma-delimited list:
|
|
<programlisting language="xml"><![CDATA[<channel id="stringOrNumberChannel" datatype="java.lang.String,java.lang.Number"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
When using the "channel" element, the creation of the channel instances will be deferred to the <classname>ChannelFactory</classname>
|
|
defined on the <classname>MessageBus</classname> (see below).
|
|
</para>
|
|
<para>
|
|
It is also possible to use more specific elements for the various channel types (as described in
|
|
<xref linkend="api-messagechannel"/>). Depending on the channel, these may provide additional configuration
|
|
options. Examples of each are shown below.
|
|
</para>
|
|
<section id="namespace-channel-queuechannel">
|
|
<title>The <queue-channel/> element</title>
|
|
<para>
|
|
To create a <classname>QueueChannel</classname>, use the "queue-channel" element.
|
|
By using this element, you can also specify the channel's capacity:
|
|
<programlisting language="xml"><queue-channel id="exampleChannel" capacity="25"/></programlisting>
|
|
</para>
|
|
</section>
|
|
<section id="namespace-channel-prioritychannel">
|
|
<title>The <priority-channel/> element</title>
|
|
<para>
|
|
To create a <classname>PriorityChannel</classname>, use the "priority-channel" element:
|
|
<programlisting language="xml"><![CDATA[<priority-channel id="exampleChannel"/>]]></programlisting>
|
|
By default, the channel will consult the <classname>MessagePriority</classname> value in the
|
|
message's header. However, a custom <interfacename>Comparator</interfacename> reference may be
|
|
provided instead. Also, note that the <classname>PriorityChannel</classname> (like the other types)
|
|
does support the "datatype" attribute. As with the "queue-channel", it also supports a "capacity" attribute.
|
|
The following example demonstrates all of these:
|
|
<programlisting language="xml"><![CDATA[<priority-channel id="exampleChannel"
|
|
datatype="example.Widget"
|
|
comparator="widgetComparator"
|
|
capacity="10"/>
|
|
]]></programlisting>
|
|
</para>
|
|
</section>
|
|
<section id="namespace-channel-rendezvouschannel">
|
|
<title>The <rendezvous-channel/> element</title>
|
|
<para>
|
|
The <classname>RendezvousChannel</classname> does not provide any additional configuration options.
|
|
<programlisting language="xml"><![CDATA[<rendezvous-channel id="exampleChannel"/>]]></programlisting>
|
|
</para>
|
|
</section>
|
|
<section id="namespace-channel-directchannel">
|
|
<title>The <direct-channel/> element</title>
|
|
<para>
|
|
The <classname>DirectChannel</classname> does not provide any additional configuration options.
|
|
<programlisting language="xml"><![CDATA[<direct-channel id="exampleChannel"/>]]></programlisting>
|
|
</para>
|
|
</section>
|
|
<section id="namespace-channel-threadlocalchannel">
|
|
<title>The <thread-local-channel/> element</title>
|
|
<para>
|
|
The <classname>ThreadLocalChannel</classname> does not provide any additional configuration options.
|
|
<programlisting language="xml"><![CDATA[<thread-local-channel id="exampleChannel"/>]]></programlisting>
|
|
</para>
|
|
</section>
|
|
<para>
|
|
Message channels may also have interceptors as described in <xref linkend="api-channelinterceptor"/>. One or
|
|
more <interceptor> elements can be added as sub-elements of <channel> (or the more specific element
|
|
types). Provide the "ref" attribute to reference any Spring-managed object that implements the
|
|
<interfacename>ChannelInterceptor</interfacename> interface:
|
|
<programlisting language="xml"><![CDATA[<channel id="exampleChannel">
|
|
]]><emphasis><![CDATA[<interceptor ref="trafficMonitoringInterceptor"/>]]></emphasis><![CDATA[
|
|
</channel>]]></programlisting>
|
|
In general, it is a good idea to define the interceptor implementations in a separate location since they
|
|
usually provide common behavior that can be reused across multiple channels.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="namespace-endpoint">
|
|
<title>Configuring Message Endpoints</title>
|
|
<para>
|
|
Each of the three endpoint types (source, target, and handler) has its own element in the namespace.
|
|
</para>
|
|
<section id="namespace-endpoint-source">
|
|
<title>The <source-endpoint/> element</title>
|
|
<para>
|
|
A <classname>SourceEndpoint</classname> connects an implementation of the <interfacename>Source</interfacename>
|
|
interface to a <interfacename>MessageChannel</interfacename>. The <source-endpoint/> therefore requires
|
|
these two references as well as the scheduling information so that the <classname>MessageBus</classname> can
|
|
manage the message-receiving tasks.
|
|
<programlisting language="xml"><![CDATA[<source-endpoint source="exampleSource" channel="exampleChannel">
|
|
<schedule period="5000"/>
|
|
</source-endpoint>]]></programlisting>
|
|
</para>
|
|
</section>
|
|
<section id="namespace-endpoint-target">
|
|
<title>The <target-endpoint/> element</title>
|
|
<para>
|
|
A <classname>TargetEndpoint</classname> connects a <interfacename>MessageChannel</interfacename> to an implementation
|
|
of the <interfacename>Target</interfacename> interface. The <target-endpoint/> requires these two references.
|
|
<programlisting language="xml"><![CDATA[<target-endpoint input-channel="exampleChannel" target="exampleTarget"/>]]></programlisting>
|
|
When the <interfacename>MessageBus</interfacename> registers the endpoint, it will activate the subscription
|
|
by assigning the endpoint to the input channel's dispatcher. The dispatcher is capable of handling multiple
|
|
endpoint subscriptions for its channel and delegates to a scheduler for managing the tasks that pull messages
|
|
from the channel and push them to the endpoints. To configure the polling period for an individual endpoint's
|
|
schedule, provide a 'schedule' sub-element with the 'period' in milliseconds:
|
|
<programlisting language="xml"><![CDATA[<target-endpoint input-channel="exampleChannel" target="exampleTarget">
|
|
]]><emphasis><![CDATA[<schedule period="3000"/>]]></emphasis><![CDATA[
|
|
</target-endpoint>]]></programlisting>
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Individual endpoint schedules only apply for "Point-to-Point" channels, since in that case only a single
|
|
subscriber needs to receive the message. On the other hand, when a Spring Integration channel is configured as
|
|
a "Publish-Subscribe" channel, then the dispatcher will drive all endpoint notifications according to its own
|
|
default schedule, and any 'schedule' element configured for those endpoints will be ignored.
|
|
</para>
|
|
</note>
|
|
<para>
|
|
The <target-endpoint/> accepts additional attributes and child elements, but since these configuration
|
|
options are also available for the <handler-endpoint/> element, they will be discussed below.
|
|
</para>
|
|
</section>
|
|
<section id="namespace-endpoint-handler">
|
|
<title>The <handler-endpoint/> element</title>
|
|
<para>
|
|
To create a Handler Endpoint instance, use the 'handler-endpoint' element with the 'input-channel' and
|
|
'handler' attributes:
|
|
<programlisting language="xml"><handler-endpoint input-channel="exampleChannel" handler="exampleHandler"/></programlisting>
|
|
</para>
|
|
<para>
|
|
The configuration above assumes that "exampleHandler" is an actual implementation of the
|
|
<interfacename>MessageHandler</interfacename> interface as described in <xref linkend="api-messagehandler"/>.
|
|
To delegate to an arbitrary method of any object, simply add the "method" attribute.
|
|
<programlisting language="xml"><handler-endpoint input-channel="exampleChannel" handler="somePojo" method="someMethod"/></programlisting>
|
|
</para>
|
|
<para>
|
|
In either case (<interfacename>MessageHandler</interfacename> or arbitrary object/method), when the handling
|
|
method returns a non-null value, the endpoint will attempt to send the reply message to an appropriate reply
|
|
channel. To determine the reply channel, it will first check if an "output-channel" was provided in the
|
|
endpoint configuration:
|
|
<programlisting language="xml"><handler-endpoint input-channel="exampleChannel" output-channel="replyChannel"
|
|
handler="somePojo" method="someMethod"/></programlisting>
|
|
If no "output-channel" is available, it will next check the message header's '<literal>returnAddress</literal>'
|
|
property. If that value is available, it will then check its type. If it is a <classname>MessageChannel</classname>,
|
|
the reply message will be sent to that channel. If it is a <classname>String</classname>, then the endpoint will
|
|
attempt to resolve the channel by performing a lookup in the <interfacename>ChannelRegistry</interfacename>.
|
|
</para>
|
|
<para>
|
|
To reverse the order so that the 'returnAddress' is given priority over the endpoint's "output-channel", then
|
|
provide the "return-address-overrides" attribute with a value of 'true':
|
|
<programlisting language="xml"><handler-endpoint input-channel="exampleChannel" output-channel="replyChannel"
|
|
handler="somePojo" method="someMethod" return-address-overrides="true"/></programlisting>
|
|
If neither is available, then a <classname>MessageHandlingException</classname> will be thrown.
|
|
</para>
|
|
</section>
|
|
<para>
|
|
Handler and Target Endpoints also support <interfacename>MessageSelectors</interfacename> as described in
|
|
<xref linkend="api-messageselector"/>. To configure a selector with namespace support, simply add the
|
|
"selector" attribute to the endpoint definition and reference an implementation of the
|
|
<interfacename>MessageSelector</interfacename> interface.
|
|
<programlisting language="xml"><![CDATA[<handler-endpoint id="endpoint" input-channel="channel" handler="handler"
|
|
selector="exampleSelector"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
Another important configuration option for handler and target endpoints is the concurrency policy. Each
|
|
endpoint is capable of managing a thread pool for its handler or target, and the values you provide for that
|
|
pool's core and max size can make a substantial difference in how the handler or target performs under load.
|
|
These settings are available per-endpoint since the performance characteristics of an endpoint's handler or
|
|
target 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 an endpoint that is configured with the
|
|
XML namespace support, provide the 'concurrency' sub-element and one or more of the properties shown below:
|
|
<programlisting language="xml"><![CDATA[<handler-endpoint input-channel="exampleChannel" handler="exampleHandler">
|
|
]]><emphasis><![CDATA[<concurrency core="5" max="25" queue-capacity="20" keep-alive="120"/>]]></emphasis><![CDATA[
|
|
</handler-endpoint>]]></programlisting>
|
|
Recall the default concurrency policy values as listed in <xref linkend="api-messagebus-concurrencypolicy"/>.
|
|
If no concurrency settings are provided (i.e. a <emphasis>null</emphasis>
|
|
<classname>ConcurrencyPolicy</classname>), the endpoint's handler or target will be invoked in the caller's thread.
|
|
Note that the "caller" is usually the dispatcher except in the case of a <classname>DirectChannel</classname>
|
|
(see <xref linkend="api-messagechannel-directchannel"/> for more detail).
|
|
</para>
|
|
<tip>
|
|
<para>
|
|
For the concurrency settings, the default queue capacity of 0 triggers the creation of a
|
|
<classname>SynchronousQueue</classname>. In many cases, this is preferable since the direct handoff eliminates
|
|
the chance of a message handling task being "stuck" in the queue (thread pool executors will favor adding to the
|
|
queue rather than increasing the pool size). Specifically, whenever a dispatcher for a Point-to-Point channel
|
|
has more than one subscribed endpoint, a task that is rejected due to an exhausted thread pool can be handled
|
|
immediately by another endpoint whose pool has one or more threads available. On the other hand, when a
|
|
particular channel/endpoint may be expecting bursts of activity, setting a queue capacity value might be the
|
|
best way to accommodate the volume.
|
|
</para>
|
|
</tip>
|
|
</section>
|
|
|
|
<section id="namespace-messagebus">
|
|
<title>Configuring the Message Bus</title>
|
|
<para>
|
|
As described in <xref linkend="api-messagebus"/>, the <classname>MessageBus</classname> plays a central role.
|
|
Nevertheless, its configuration is quite simple since it is primarily concerned with managing internal details
|
|
based on the configuration of channels and endpoints. The bus is aware of its host application context, and
|
|
therefore is also capable of auto-detecting the channels and endpoints. Typically, the
|
|
<classname>MessageBus</classname> can be configured with a single empty element:
|
|
<programlisting language="xml"><message-bus/></programlisting>
|
|
</para>
|
|
<para>
|
|
The Message Bus provides default error handling for its components in the form of a configurable error channel,
|
|
and the 'message-bus' element accepts a reference with its 'error-channel' attribute:
|
|
<programlisting language="xml"><![CDATA[<message-bus error-channel="errorChannel"/>
|
|
|
|
<channel id="errorChannel" publish-subscribe="true" capacity="500"/>]]></programlisting>
|
|
When exceptions occur in a concurrent endpoint's execution of its <interfacename>MessageHandler</interfacename>
|
|
callback, those exceptions will be wrapped in <classname>ErrorMessages</classname> and sent to the Message Bus'
|
|
'errorChannel' by default. To enable global error handling, simply register a handler on that channel. For
|
|
example, you can configure Spring Integration's <classname>PayloadTypeRouter</classname> as the handler of
|
|
an endpoint that is subscribed to the 'errorChannel'. That router can then spread the error messages across
|
|
multiple channels based on <classname>Exception</classname> type. However, since most of the errors will already
|
|
have been wrapped in <classname>MessageDeliveryException</classname> or <classname>MessageHandlingException</classname>,
|
|
the <classname>RootCauseErrorMessageRouter</classname> is typically a better option.
|
|
</para>
|
|
<para>
|
|
The 'message-bus' element accepts several more optional attributes. First, you can control whether the
|
|
<classname>MessageBus</classname> will be started automatically (the default) or will require explicit startup
|
|
by invoking its <methodname>start()</methodname> method (<classname>MessageBus</classname> implements
|
|
Spring's <interfacename>Lifecycle</interfacename> interface):
|
|
<programlisting language="xml"><![CDATA[<message-bus auto-startup="false"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
Another configurable property is the size of the dispatcher thread pool. The dispatcher threads are responsible
|
|
for polling channels and then passing the messages to handlers.
|
|
<programlisting language="xml"><![CDATA[<message-bus dispatcher-pool-size="25"/>]]></programlisting>
|
|
When the endpoints are concurrency-enabled as described in the previous section, the invocation of the handling
|
|
methods will happen within the handler thread pool and not the dispatcher pool. However, when no concurrency
|
|
policy is provided to an endpoint, then it will be invoked in the dispatcher's thread (with the exception of
|
|
<classname>DirectChannels</classname>).
|
|
</para>
|
|
<para>
|
|
Also, the Message Bus is capable of automatically creating channel instances if an endpoint registers a
|
|
subscription by providing the name of a channel that the bus does not recognize.
|
|
<programlisting language="xml"><![CDATA[<message-bus auto-create-channels="true"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
Finally, the type of channel that gets created automatically by the bus can be customized by using the
|
|
"channel-factory" attribute on the "message-bus" definition as in the following example:
|
|
<programlisting language="xml"><![CDATA[<message-bus channel-factory="channelFactoryBean"/>
|
|
|
|
<beans:bean id="channelFactoryBean"
|
|
class="org.springframework.integration.channel.factory.PriorityChannelFactory"/>]]></programlisting>
|
|
With this definition, all the channels created automatically will be <classname>PriorityChannel</classname> instances.
|
|
Without the "channel-factory" element, the Message Bus will assume a default <classname>QueueChannelFactory</classname>.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="namespace-adapters">
|
|
<title>Configuring Adapters</title>
|
|
<para>
|
|
The most convenient way to configure Source and Target adapters is by using the namespace support. The
|
|
following examples demonstrate the namespace-based configuration of several sources and targets:
|
|
<programlisting language="xml"><![CDATA[<jms-source id="jmsSource" connection-factory="connFactory" destination="inQueue"/>
|
|
|
|
<!-- using the default "connectionFactory" reference -->
|
|
<jms-target id="jmsTarget" destination="outQueue"/>
|
|
|
|
<file-source id="fileSource" directory="/tmp/in"/>
|
|
|
|
<file-target id="fileTarget" directory="/tmp/out"/>
|
|
|
|
<rmi-source id="rmiSource" request-channel="rmiSourceInput"/>
|
|
|
|
<rmi-target id="rmiTarget"
|
|
local-channel="rmiTargetOutput"
|
|
remote-channel="someRemoteChannel"
|
|
host="somehost"/>
|
|
|
|
<httpinvoker-source id="httpSource" name="/some/path" request-channel="httpInvokerInput"/>
|
|
|
|
<httpinvoker-target id="httpTarget" channel="httpInvokerOutput" url="http://somehost/test"/>
|
|
|
|
<mail-target id="mailTarget" host="somehost" username="someuser" password="somepassword"/>
|
|
|
|
<ws-target id="wsTarget" uri="http://example.org" channel="wsOutput"/>
|
|
|
|
<ftp-source id="ftpSource"
|
|
host="example.org"
|
|
username="someuser"
|
|
password="somepassword"
|
|
local-working-directory="/some/path"
|
|
remote-working-directory="/some/path"/>
|
|
]]></programlisting>
|
|
</para>
|
|
<para>
|
|
In the examples above, notice that simple implementations of the <interfacename>Source</interfacename>
|
|
and <interfacename>Target</interfacename> interfaces do not accept any 'channel' references. To
|
|
connect such sources and targets to a channel, register them within an endpoint. For example, here
|
|
is a File source with an endpoint whose polling will be scheduled to execute every 30 seconds by the
|
|
<classname>MessageBus</classname>.
|
|
<programlisting language="xml"><![CDATA[<source-endpoint source="fileSource" channel="exampleChannel">
|
|
<schedule period="30000"/>
|
|
</source-endpoint>
|
|
|
|
<file-source id="fileSource" directory="/tmp/in"/>
|
|
]]></programlisting>
|
|
Likewise, here is an example of a JMS target that is registered with a target-endpoint whose Messages
|
|
will be received from the "exampleChannel" that is polled every 500 milliseconds.
|
|
<programlisting language="xml"><![CDATA[<target-endpoint input-channel="exampleChannel" target="jmsTarget">
|
|
<schedule period="500"/>
|
|
</target-endpoint>
|
|
|
|
<jms-target id="jmsTarget" destination="targetDestination"/>
|
|
]]></programlisting>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="namespace-annotationdriven">
|
|
<title>Enabling Annotation-Driven Configuration</title>
|
|
<para>
|
|
The next section will describe Spring Integration's support for annotation-driven configuration. To enable
|
|
those features, add this single element to the XML-based configuration:
|
|
<programlisting language="xml"><annotation-driven/></programlisting>
|
|
</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="annotations">
|
|
<title>Annotations</title>
|
|
<para>
|
|
In addition to the XML namespace support for configuring Message Endpoints, it is also possible to use
|
|
annotations. The class-level <interfacename>@MessageEndpoint</interfacename> annotation indicates that the
|
|
annotated class is capable of being registered as an endpoint, and the method-level
|
|
<interfacename>@Handler</interfacename> annotation indicates that the annotated method is capable of handling
|
|
a message.
|
|
<programlisting language="java">@MessageEndpoint(input="fooChannel")
|
|
public class FooService {
|
|
|
|
@Handler
|
|
public void processMessage(Message message) {
|
|
...
|
|
}
|
|
}</programlisting>
|
|
</para>
|
|
<para>
|
|
In most cases, the annotated handler method should not require the <classname>Message</classname> type as its
|
|
parameter. Instead, the method parameter type can match the message's payload type.
|
|
<programlisting language="java">@MessageEndpoint(input="fooChannel")
|
|
public class FooService {
|
|
|
|
@Handler
|
|
public void bar(<emphasis>Foo foo</emphasis>) {
|
|
...
|
|
}
|
|
}</programlisting>
|
|
</para>
|
|
<para>
|
|
When the method parameter should be mapped from a value in the <classname>MessageHeader</classname>, another
|
|
option is to use the <interfacename>@HeaderAttribute</interfacename> and/or
|
|
<interfacename>@HeaderProperty</interfacename> parameter annotations.
|
|
<programlisting language="java">@MessageEndpoint(input="fooChannel")
|
|
public class FooService {
|
|
|
|
@Handler
|
|
public void bar(<emphasis>@HeaderAttribute("fooAttrib") Foo foo</emphasis>) {
|
|
...
|
|
}
|
|
}</programlisting>
|
|
<programlisting language="java">@MessageEndpoint(input="fooChannel")
|
|
public class FooService {
|
|
|
|
@Handler
|
|
public void bar(<emphasis>@HeaderProperty("foo") String input</emphasis>) {
|
|
...
|
|
}
|
|
}</programlisting>
|
|
</para>
|
|
<para>
|
|
As described in the previous section, when the handler method returns a non-null value, the endpoint will
|
|
attempt to send a reply. This is consistent across both configuration options (namespace and annotations) in that
|
|
the the endpoint's output channel will be used if available, and the message header's 'returnAddress' value will be
|
|
the fallback. To configure the output channel for an annotation-driven endpoint, provide the 'output'
|
|
attribute on the <interfacename>@MessageEndpoint</interfacename>.
|
|
<programlisting language="java">@MessageEndpoint(input="exampleChannel", output="replyChannel")</programlisting>
|
|
</para>
|
|
<para>
|
|
Just as the 'schedule' sub-element and its 'period' attribute can be provided for a namespace-based
|
|
endpoint, the <interfacename>@Polled</interfacename> annotation can be provided with the
|
|
<interfacename>@MessageEndpoint</interfacename> annotation.
|
|
<programlisting language="java">@MessageEndpoint(input="exampleChannel")
|
|
@Polled(period=3000)
|
|
public class FooService {
|
|
...
|
|
}</programlisting>
|
|
Likewise, <interfacename>@Concurrency</interfacename> provides an annotation-based equivalent of the
|
|
<concurrency/> element:
|
|
<programlisting language="java">@MessageEndpoint(input="fooChannel")
|
|
@Concurrency(coreSize=5, maxSize=20)
|
|
public class FooService {
|
|
|
|
@Handler
|
|
public void bar(Foo foo) {
|
|
...
|
|
}
|
|
}</programlisting>
|
|
</para>
|
|
<para>
|
|
Two additional annotations are supported, and both act as a special form of handler method:
|
|
<interfacename>@Router</interfacename> and <interfacename>@Splitter</interfacename>. As with the
|
|
<interfacename>@Handler</interfacename> annotation, methods annotated with either of these two annotations can
|
|
either accept the <classname>Message</classname> itself or the message payload type as the parameter.
|
|
When using the <interfacename>@Router</interfacename> annotation, the annotated method can return either the
|
|
<interfacename>MessageChannel</interfacename> or <classname>String</classname> type. In the case of the latter,
|
|
the endpoint will resolve the channel name as it does for the default output. Additionally, the method can return
|
|
either a single value or a collection. When a collection is returned, the reply message will be sent to multiple
|
|
channels. To summarize, the following method signatures are all valid.
|
|
<programlisting language="java">@Router
|
|
public MessageChannel route(Message message) {...}
|
|
|
|
@Router
|
|
public List<MessageChannel> route(Message message) {...}
|
|
|
|
@Router
|
|
public String route(Foo payload) {...}
|
|
|
|
@Router
|
|
public List<String> route(Foo payload) {...}</programlisting>
|
|
</para>
|
|
<para>
|
|
In addition to payload-based routing, a common requirement is to route based on metadata available within the
|
|
message header as either a property or attribute. Rather than requiring use of the
|
|
<interfacename>Message</interfacename> type as the method parameter, the <interfacename>@Router</interfacename>
|
|
annotation may also use the same parameter annotations that were introduced above.
|
|
<programlisting language="java">@Router
|
|
public String route(@HeaderProperty("customerType") String customerType)
|
|
|
|
@Router
|
|
public List<String> route(@HeaderAttribute("orderStatus") OrderStatus status)</programlisting>
|
|
</para>
|
|
<para>
|
|
The <interfacename>@Splitter</interfacename> annotation is also 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>
|
|
<para>
|
|
The <interfacename>@Publisher</interfacename> annotation is convenient for sending messages with AOP
|
|
<emphasis>after-returning advice</emphasis>. For example, each time the following method is invoked, its return
|
|
value will be sent to the "fooChannel":
|
|
<programlisting language="java"><![CDATA[@Publisher(channel="fooChannel")
|
|
public String foo() {
|
|
return "bar";
|
|
}]]></programlisting>
|
|
</para>
|
|
<para>
|
|
Similarly, the <interfacename>@Subscriber</interfacename> annotation triggers the retrieval of messages from a
|
|
channel, and the payload of each message will then be sent as input to an arbitrary method. This is one of the
|
|
simplest ways to configure asynchronous, event-driven behavior:
|
|
<programlisting language="java"><![CDATA[@Subscriber(channel="fooChannel")
|
|
public void log(String foo) {
|
|
System.out.println(foo);
|
|
}]]></programlisting>
|
|
</para>
|
|
</section>
|
|
</chapter> |