Updated endpoint and channel documentation.

This commit is contained in:
Mark Fisher
2008-05-22 23:26:31 +00:00
parent 32519f4ae8
commit 2e984dbb3b
2 changed files with 180 additions and 100 deletions

View File

@@ -100,26 +100,61 @@
defined on the <classname>MessageBus</classname> (see below). defined on the <classname>MessageBus</classname> (see below).
</para> </para>
<para> <para>
To specificially create a <classname>QueueChannel</classname>, use the "queue-channel" element. It is also possible to use more specific elements for the various channel types (as described in
By using this element, you can also specify the channel's capacity: <xref linkend="api-messagechannel"/>). Depending on the channel, these may provide additional configuration
<programlisting language="xml">&lt;queue-channel id="exampleChannel" capacity="100"/&gt;</programlisting> options. Examples of each are shown below.
</para> </para>
<para> <section id="namespace-channel-queuechannel">
To create a <classname>PriorityChannel</classname>, use the "priority-channel" element: <title>The &lt;queue-channel/&gt; element</title>
<programlisting language="xml"><![CDATA[<priority-channel id="exampleChannel"/>]]></programlisting> <para>
By default, the channel will consult the <classname>MessagePriority</classname> value in the To create a <classname>QueueChannel</classname>, use the "queue-channel" element.
message's header. However, a custom <interfacename>Comparator</interfacename> reference may be By using this element, you can also specify the channel's capacity:
provided instead. Also, the <classname>PriorityChannel</classname> does support the "datatype" <programlisting language="xml">&lt;queue-channel id="exampleChannel" capacity="25"/&gt;</programlisting>
attribute. The following example demonstrates both: </para>
<programlisting language="xml"><![CDATA[<priority-channel id="exampleChannel" </section>
datatype="example.Widget" comparator="widgetComparator"/> <section id="namespace-channel-prioritychannel">
<title>The &lt;priority-channel/&gt; 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> ]]></programlisting>
</para> </para>
</section>
<section id="namespace-channel-rendezvouschannel">
<title>The &lt;rendezvous-channel/&gt; 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 &lt;direct-channel/&gt; 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 &lt;thread-local-channel/&gt; 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> <para>
Message channels may also have interceptors as described in <xref linkend="api-channelinterceptor"/>. One or Message channels may also have interceptors as described in <xref linkend="api-channelinterceptor"/>. One or
more &lt;interceptor&gt; elements can be added as sub-elements of &lt;channel&gt;. Provide the "ref" attribute more &lt;interceptor&gt; elements can be added as sub-elements of &lt;channel&gt; (or the more specific element
to reference any Spring-managed object that implements the <interfacename>ChannelInterceptor</interfacename> types). Provide the "ref" attribute to reference any Spring-managed object that implements the
interface: <interfacename>ChannelInterceptor</interfacename> interface:
<programlisting language="xml"><![CDATA[<channel id="exampleChannel"> <programlisting language="xml"><![CDATA[<channel id="exampleChannel">
]]><emphasis><![CDATA[<interceptor ref="trafficMonitoringInterceptor"/>]]></emphasis><![CDATA[ ]]><emphasis><![CDATA[<interceptor ref="trafficMonitoringInterceptor"/>]]></emphasis><![CDATA[
</channel>]]></programlisting> </channel>]]></programlisting>
@@ -131,83 +166,116 @@
<section id="namespace-endpoint"> <section id="namespace-endpoint">
<title>Configuring Message Endpoints</title> <title>Configuring Message Endpoints</title>
<para> <para>
To create a Message Endpoint instance, use the 'handler-endpoint' element with the 'input-channel' and 'handler' Each of the three endpoint types (source, target, and handler) has its own element in the namespace.
attributes:
<programlisting language="xml">&lt;handler-endpoint input-channel="exampleChannel" handler="exampleHandler"/&gt;</programlisting>
</para> </para>
<para> <section id="namespace-endpoint-source">
The configuration above assumes that "exampleHandler" is an actual implementation of the <title>The &lt;source-endpoint/&gt; element</title>
<interfacename>MessageHandler</interfacename> interface as described in <xref linkend="api-messagehandler"/>. <para>
To delegate to an arbitrary method of any object, simply add the "method" attribute. A <classname>SourceEndpoint</classname> connects an implementation of the <interfacename>Source</interfacename>
<programlisting language="xml">&lt;handler-endpoint input-channel="exampleChannel" handler="somePojo" method="someMethod"/&gt;</programlisting> interface to a <interfacename>MessageChannel</interfacename>. The &lt;source-endpoint/&gt; therefore requires
</para> these two references as well as the scheduling information so that the <classname>MessageBus</classname> can
<para> manage the message-receiving tasks.
In either case (<interfacename>MessageHandler</interfacename> or arbitrary object/method), when the handling <programlisting language="xml"><![CDATA[<source-endpoint source="exampleSource" channel="exampleChannel">
method returns a non-null value, the endpoint will attempt to send the reply message to an appropriate reply <schedule period="5000"/>
channel. To determine the reply channel, it will first check for a value in the message header's </source-endpoint>]]></programlisting>
'<literal>returnAddress</literal>' property. If that value is available, it will then check its type. If it is </para>
a <classname>MessageChannel</classname>, the reply message will be sent to that channel. If it is a </section>
<classname>String</classname>, then the endpoint will attempt to resolve the channel by performing a <section id="namespace-endpoint-target">
lookup in the <interfacename>ChannelRegistry</interfacename>. If the message header does not contain a <title>The &lt;target-endpoint/&gt; element</title>
'returnAddress' property at all, then it will fallback to its own 'outputChannelName' property. If <para>
neither is available, then a <classname>MessageHandlingException</classname> will be thrown. To configure the A <classname>TargetEndpoint</classname> connects a <interfacename>MessageChannel</interfacename> to an implementation
output channel when using the XML namespace, provide the 'output-channel' attribute: of the <interfacename>Target</interfacename> interface. The &lt;target-endpoint/&gt; requires these two references.
<programlisting language="xml">&lt;handler-endpoint input-channel="exampleChannel" <programlisting language="xml"><![CDATA[<target-endpoint input-channel="exampleChannel" target="exampleTarget"/>]]></programlisting>
handler="somePojo" When the <interfacename>MessageBus</interfacename> registers the endpoint, it will activate the subscription
method="someMethod" by assigning the endpoint to the input channel's dispatcher. The dispatcher is capable of handling multiple
output-channel="replyChannel"/&gt;</programlisting> endpoint subscriptions for its channel and delegates to a scheduler for managing the tasks that pull messages
</para> from the channel and push them to the endpoints. To configure the polling period for an individual endpoint's
<para> schedule, provide a 'schedule' sub-element with the 'period' in milliseconds:
Endpoints also support <interfacename>MessageSelectors</interfacename> as described in <programlisting language="xml"><![CDATA[<target-endpoint input-channel="exampleChannel" target="exampleTarget"/>
<xref linkend="api-messageselector"/>. To configure selectors with namespace support, simply add one or more
&lt;selector&gt; sub-elements to the endpoint definition:
<programlisting language="xml"><![CDATA[<handler-endpoint id="endpoint" input-channel="channel" handler="handler">
]]><emphasis><![CDATA[<selector ref="exampleSelector"/>]]></emphasis><![CDATA[
</handler-endpoint>]]></programlisting>
</para>
<para>
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[<handler-endpoint input-channel="exampleChannel" handler="exampleHandler"/>
]]><emphasis><![CDATA[<schedule period="3000"/>]]></emphasis><![CDATA[ ]]><emphasis><![CDATA[<schedule period="3000"/>]]></emphasis><![CDATA[
</handler-endpoint>]]></programlisting> </handler-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> </para>
</note> <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 &lt;target-endpoint/&gt; accepts additional attributes and child elements, but since these configuration
options are also available for the &lt;handler-endpoint/&gt; element, they will be discussed below.
</para>
</section>
<section id="namespace-endpoint-handler">
<title>The &lt;handler-endpoint/&gt; element</title>
<para>
To create a Handler Endpoint instance, use the 'handler-endpoint' element with the 'input-channel' and
'handler' attributes:
<programlisting language="xml">&lt;handler-endpoint input-channel="exampleChannel" handler="exampleHandler"/&gt;</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">&lt;handler-endpoint input-channel="exampleChannel" handler="somePojo" method="someMethod"/&gt;</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">&lt;handler-endpoint input-channel="exampleChannel" output-channel="replyChannel"
handler="somePojo" method="someMethod"/&gt;</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">&lt;handler-endpoint input-channel="exampleChannel" output-channel="replyChannel"
handler="somePojo" method="someMethod" return-address-overrides="true"/&gt;</programlisting>
If neither is available, then a <classname>MessageHandlingException</classname> will be thrown.
</para>
</section>
<para> <para>
One of the most important configuration options for endpoints is the concurrency policy. Each endpoint is Handler and Target Endpoints also support <interfacename>MessageSelectors</interfacename> as described in
capable of managing a thread pool for its handler, and the values you provide for that pool's core and max <xref linkend="api-messageselector"/>. To configure a selector with namespace support, simply add the
size can make a substantial difference in how the handler performs under load. These settings are available "selector" attribute to the endpoint definition and reference an implementation of the
per-endpoint since the performance characteristics of an endpoint's handler is one of the major factors to <interfacename>MessageSelector</interfacename> interface.
consider (the other major factor being the expected volume on the channel to which the endpoint subscribes). <programlisting language="xml"><![CDATA[<handler-endpoint id="endpoint" input-channel="channel" handler="handler"
To enable concurrency for an endpoint that is configured with the XML namespace support, provide the selector="exampleSelector"/>]]></programlisting>
'concurrency' sub-element and one or more of the properties shown below: </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"/> <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[ ]]><emphasis><![CDATA[<concurrency core="5" max="25" queue-capacity="20" keep-alive="120"/>]]></emphasis><![CDATA[
</handler-endpoint>]]></programlisting> </handler-endpoint>]]></programlisting>
Recall the default concurrency policy values as listed in <xref linkend="api-messagebus-concurrencypolicy"/>. 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> If no concurrency settings are provided (i.e. a <emphasis>null</emphasis>
<classname>ConcurrencyPolicy</classname>), the endpoint's handler will be invoked in the caller's thread. <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> </para>
<tip> <tip>
<para> <para>
The default queue capacity of 0 triggers the creation of a <classname>SynchronousQueue</classname>. In many For the concurrency settings, the default queue capacity of 0 triggers the creation of a
cases, this is preferable since the direct handoff eliminates the chance of a message handling task being <classname>SynchronousQueue</classname>. In many cases, this is preferable since the direct handoff eliminates
"stuck" in the queue (thread pool executors will favor adding to the queue rather than increasing the pool the chance of a message handling task being "stuck" in the queue (thread pool executors will favor adding to the
size). Specifically, whenever a dispatcher for a Point-to-Point channel has more than one subscribed queue rather than increasing the pool size). Specifically, whenever a dispatcher for a Point-to-Point channel
endpoint, a task that is rejected due to an exhausted thread pool can be handled immediately by another has more than one subscribed endpoint, a task that is rejected due to an exhausted thread pool can be handled
endpoint whose pool has one or more threads available. On the other hand, when a particular channel/endpoint immediately by another endpoint whose pool has one or more threads available. On the other hand, when a
may be expecting bursts of activity, setting a queue capacity value might be the best way to accommodate the particular channel/endpoint may be expecting bursts of activity, setting a queue capacity value might be the
volume. best way to accommodate the volume.
</para> </para>
</tip> </tip>
</section> </section>
@@ -228,28 +296,40 @@
<programlisting language="xml"><![CDATA[<message-bus error-channel="errorChannel"/> <programlisting language="xml"><![CDATA[<message-bus error-channel="errorChannel"/>
<channel id="errorChannel" publish-subscribe="true" capacity="500"/>]]></programlisting> <channel id="errorChannel" publish-subscribe="true" capacity="500"/>]]></programlisting>
When exceptions occur in an endpoint's execution of its <interfacename>MessageHandler</interfacename> callback, When exceptions occur in a concurrent endpoint's execution of its <interfacename>MessageHandler</interfacename>
those exceptions will be wrapped in <classname>ErrorMessages</classname> and sent to the Message Bus' 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 '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 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 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. 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>
<para> <para>
The 'message-bus' element accepts two more optional attributes. First is the size of the dispatcher thread The 'message-bus' element accepts several more optional attributes. First, you can control whether the
pool. The dispatcher threads are responsible for polling channels and then passing the messages to handlers. <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 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. Finally, the Message Bus is methods will happen within the handler thread pool and not the dispatcher pool. However, when no concurrency
capable of automatically creating channel instances if an endpoint registers a subscription by providing the policy is provided to an endpoint, then it will be invoked in the dispatcher's thread (with the exception of
name of a channel that the bus does not recognize. <classname>DirectChannels</classname>).
<programlisting language="xml"><![CDATA[<message-bus dispatcher-pool-size="25" auto-create-channels="true"/>]]></programlisting> </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>
<para> <para>
The type of channel that gets created automatically by the bus can be customized by using the "channel-factory" Finally, the type of channel that gets created automatically by the bus can be customized by using the
element on the "message-bus" definition as in the following example: "channel-factory" attribute on the "message-bus" definition as in the following example:
<programlisting language="xml"><![CDATA[<message-bus> <programlisting language="xml"><![CDATA[<message-bus channel-factory="channelFactoryBean"/>
<channel-factory ref="channelFactoryBean"/>
</message-bus>
<beans:bean id="channelFactoryBean" <beans:bean id="channelFactoryBean"
class="org.springframework.integration.channel.factory.PriorityChannelFactory"/>]]></programlisting> class="org.springframework.integration.channel.factory.PriorityChannelFactory"/>]]></programlisting>

View File

@@ -169,7 +169,7 @@ target.send(new StringMessage("test"));</programlisting>
Spring Integration provides several different implementations of the Spring Integration provides several different implementations of the
<interfacename>MessageChannel</interfacename> interface. Each is briefly described in the sections below. <interfacename>MessageChannel</interfacename> interface. Each is briefly described in the sections below.
</para> </para>
<section> <section id="api-messagechannel-queuechannel">
<title>QueueChannel</title> <title>QueueChannel</title>
<para> <para>
The <classname>QueueChannel</classname> implementation wraps a queue. It provides a no-argument constructor The <classname>QueueChannel</classname> implementation wraps a queue. It provides a no-argument constructor
@@ -185,7 +185,7 @@ target.send(new StringMessage("test"));</programlisting>
<methodname>receive()</methodname> will block indefinitely. <methodname>receive()</methodname> will block indefinitely.
</para> </para>
</section> </section>
<section> <section id="api-messagechannel-prioritychannel">
<title>PriorityChannel</title> <title>PriorityChannel</title>
<para> <para>
Whereas the <classname>QueueChannel</classname> enforces first-in/first-out (FIFO) ordering, the Whereas the <classname>QueueChannel</classname> enforces first-in/first-out (FIFO) ordering, the
@@ -196,7 +196,7 @@ target.send(new StringMessage("test"));</programlisting>
<classname>PriorityChannel</classname>'s constructor. <classname>PriorityChannel</classname>'s constructor.
</para> </para>
</section> </section>
<section> <section id="api-messagechannel-rendezvouschannel">
<title>RendezvousChannel</title> <title>RendezvousChannel</title>
<para> <para>
The <classname>RendezvousChannel</classname> enables a "direct-handoff" scenario where a sender will block The <classname>RendezvousChannel</classname> enables a "direct-handoff" scenario where a sender will block
@@ -216,7 +216,7 @@ target.send(new StringMessage("test"));</programlisting>
call receive (optionally providing a timeout value) in order to block while waiting for a reply Message. call receive (optionally providing a timeout value) in order to block while waiting for a reply Message.
</para> </para>
</section> </section>
<section> <section id="api-messagechannel-directchannel">
<title>DirectChannel</title> <title>DirectChannel</title>
<para> <para>
The <classname>DirectChannel</classname> is significantly different than the channel implementations described The <classname>DirectChannel</classname> is significantly different than the channel implementations described
@@ -229,7 +229,7 @@ target.send(new StringMessage("test"));</programlisting>
that transaction (commit or rollback). that transaction (commit or rollback).
</para> </para>
</section> </section>
<section> <section id="api-messagechannel-threadlocalchannel">
<title>ThreadLocalChannel</title> <title>ThreadLocalChannel</title>
<para> <para>
The final channel implementation type is <classname>ThreadLocalChannel</classname>. This channel also delegates The final channel implementation type is <classname>ThreadLocalChannel</classname>. This channel also delegates