Come up to BRITS
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<?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="adapters">
|
||||
<title>Channel Adapters</title>
|
||||
|
||||
@@ -36,7 +37,7 @@
|
||||
a reference to a <interfacename>MessageChannel</interfacename> instance. The adapter accepts additional
|
||||
properties such as: period, initialDelay, maxMessagesPerTask, and sendTimeout. The following example defines a
|
||||
JMS source adapter that polls every 5 seconds and then sends to the "exampleChannel":
|
||||
<programlisting><![CDATA[<bean class="org.springframework.integration.adapter.jms.JmsPollingSourceAdapter">
|
||||
<programlisting language="xml"><![CDATA[<bean class="org.springframework.integration.adapter.jms.JmsPollingSourceAdapter">
|
||||
<constructor-arg ref="jmsTemplate"/>
|
||||
<property name="channel" ref="exampleChannel"/>
|
||||
<property name="period" value="5000"/>
|
||||
@@ -50,7 +51,7 @@
|
||||
<interfacename>Destination</interfacename> (or 'destinationName'). The following example defines a JMS
|
||||
message-driven source adapter that receives from the JMS queue called "exampleQueue" and then sends to
|
||||
the Spring Integration channel named "exampleChannel":
|
||||
<programlisting><![CDATA[<bean class="org.springframework.integration.adapter.jms.JmsMessageDrivenSourceAdapter">
|
||||
<programlisting language="xml"><![CDATA[<bean class="org.springframework.integration.adapter.jms.JmsMessageDrivenSourceAdapter">
|
||||
<property name="connectionFactory" ref="connectionFactory"/>
|
||||
<property name="destinationName" value="exampleQueue"/>
|
||||
<property name="channel" ref="exampleChannel"/>
|
||||
@@ -78,7 +79,7 @@
|
||||
However, since it is adapting a <interfacename>MessageChannel</interfacename>, there is no need to specify
|
||||
the <emphasis>serviceInterface</emphasis>. Likewise, the <emphasis>serviceName</emphasis> is automatically
|
||||
generated based on the channel name. Therefore, creating the adapter is as simple as providing a reference
|
||||
to its channel: <programlisting>RmiSourceAdapter rmiSourceAdapter = new RmiSourceAdapter(channel);
|
||||
to its channel: <programlisting language="java">RmiSourceAdapter rmiSourceAdapter = new RmiSourceAdapter(channel);
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
@@ -87,7 +88,7 @@
|
||||
is already known, the only required information is the URL. The URL should include the host, port (default is
|
||||
'1099'), and 'serviceName'. The 'serviceName' must match that created by the
|
||||
<classname>RmiSourceAdapter</classname> (the prefix is available as a constant).
|
||||
<programlisting>String url = "http://somehost:1099/" + RmiSourceAdapter.SERVICE_NAME_PREFIX + "someChannel";
|
||||
<programlisting language="java">String url = "http://somehost:1099/" + RmiSourceAdapter.SERVICE_NAME_PREFIX + "someChannel";
|
||||
RmiTargetAdapter rmiTargetAdapter = new RmiTargetAdapter(url);
|
||||
</programlisting>
|
||||
</para>
|
||||
@@ -101,7 +102,7 @@ RmiTargetAdapter rmiTargetAdapter = new RmiTargetAdapter(url);
|
||||
<interfacename>HandlerMapping</interfacename>. For example, the following would be exposed at the path
|
||||
"http://somehost/path-mapped-to-dispatcher-servlet/httpInvokerAdapter" when a simple
|
||||
<classname>BeanNameUrlHandlerMapping</classname> strategy is enabled:
|
||||
<programlisting><![CDATA[<bean name="/httpInvokerAdapter"
|
||||
<programlisting language="xml"><![CDATA[<bean name="/httpInvokerAdapter"
|
||||
class="org.springframework.integration.adapter.httpinvoker.HttpInvokerSourceAdapter">
|
||||
<constructor-arg ref="someChannel"/>
|
||||
</bean>]]></programlisting>
|
||||
@@ -117,13 +118,13 @@ RmiTargetAdapter rmiTargetAdapter = new RmiTargetAdapter(url);
|
||||
<para>
|
||||
The <classname>FileSourceAdapter</classname> extends the generic <classname>PollingSourceAdapter</classname>
|
||||
(just as the polling JMS adapter does). It requires the following constructor arguments:
|
||||
<programlisting>public FileSourceAdapter(File directory, MessageChannel channel, int period)</programlisting>
|
||||
<programlisting language="java">public FileSourceAdapter(File directory, MessageChannel channel, int period)</programlisting>
|
||||
Optional properties include 'initialDelay' and 'maxMessagesPerTask'.
|
||||
</para>
|
||||
<para>
|
||||
The <classname>FileTargetAdapter</classname> constructor only requires the 'directory' argument. The target
|
||||
adapter also accepts an implementation of the <interfacename>FileNameGenerator</interfacename> strategy that
|
||||
defines the following method: <programlisting>String generateFileName(Message message)</programlisting>
|
||||
defines the following method: <programlisting language="java">String generateFileName(Message message)</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
<section id="adapters-ftp">
|
||||
@@ -132,7 +133,7 @@ RmiTargetAdapter rmiTargetAdapter = new RmiTargetAdapter(url);
|
||||
To poll a directory with FTP, configure an instance of <classname>FtpSourceAdapter</classname>. The adapter
|
||||
expects a number of properties for connecting to the FTP server (as shown below) as well as the
|
||||
'channel' and the 'period' for polling. For example, the following adapter would poll every 30 seconds:
|
||||
<programlisting><![CDATA[<bean id="ftpSource"
|
||||
<programlisting language="xml"><![CDATA[<bean id="ftpSource"
|
||||
class="org.springframework.integration.adapter.ftp.FtpSourceAdapter">
|
||||
<property name="host" value="example.org"/>
|
||||
<property name="username" value="someuser"/>
|
||||
@@ -157,12 +158,12 @@ RmiTargetAdapter rmiTargetAdapter = new RmiTargetAdapter(url);
|
||||
<para>
|
||||
The adapter also delegates to a <interfacename>MailHeaderGenerator</interfacename> for providing the
|
||||
mail's properties, such as the recipients (TO, CC, and BCC), the from/reply-to, and the subject.
|
||||
<programlisting><![CDATA[public interface MailHeaderGenerator {
|
||||
<programlisting language="java"><![CDATA[public interface MailHeaderGenerator {
|
||||
void populateMailMessageHeader(MailMessage mailMessage, Message<?> message);
|
||||
}]]></programlisting>
|
||||
The default implementation will look for attributes in the <classname>MessageHeader</classname> with
|
||||
the following constants defining the keys:
|
||||
<programlisting>MailAttributeKeys.SUBJECT
|
||||
<programlisting language="java">MailAttributeKeys.SUBJECT
|
||||
MailAttributeKeys.TO
|
||||
MailAttributeKeys.CC
|
||||
MailAttributeKeys.BCC
|
||||
@@ -173,7 +174,7 @@ MailAttributeKeys.REPLY_TO</programlisting>
|
||||
A static implementation is also available out-of-the-box and may be useful for testing. However, when
|
||||
customizing, the properties would typically be generated dynamically based on the message itself. The
|
||||
following is an example of a configured mail adapter.
|
||||
<programlisting><![CDATA[<bean id="mailTargetAdapter"
|
||||
<programlisting language="xml"><![CDATA[<bean id="mailTargetAdapter"
|
||||
class="org.springframework.integration.adapter.mail.MailTargetAdapter">
|
||||
<property name="mailSender" ref="javaMailSender"/>
|
||||
<property name="headerGenerator" ref="dynamicMailMessageHeaderGenerator"/>
|
||||
@@ -189,7 +190,7 @@ MailAttributeKeys.REPLY_TO</programlisting>
|
||||
<classname>String</classname> or <interfacename>javax.xml.transform.Source</interfacename> as the message
|
||||
payload. The latter provides support for any implementation of the <interfacename>Marshaller</interfacename>
|
||||
and <interfacename>Unmarshaller</interfacename> interfaces. Both require the URI of the Web Service to be
|
||||
called.<programlisting>simpleAdapter = new SimpleWebServiceTargetAdapter(uri);
|
||||
called.<programlisting language="java">simpleAdapter = new SimpleWebServiceTargetAdapter(uri);
|
||||
|
||||
marshallingAdapter = new MarshallingWebServiceTargetAdapter(uri, marshaller);
|
||||
</programlisting>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?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>
|
||||
|
||||
@@ -27,7 +28,7 @@
|
||||
<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><![CDATA[<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
<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
|
||||
@@ -40,7 +41,7 @@
|
||||
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><emphasis><beans:beans xmlns="http://www.springframework.org/schema/integration"</emphasis><![CDATA[
|
||||
<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
|
||||
@@ -62,20 +63,20 @@
|
||||
<title>Configuring Message Channels</title>
|
||||
<para>
|
||||
To create a Message Channel instance, you can use the generic 'channel' element:
|
||||
<programlisting><channel id="exampleChannel"/></programlisting>
|
||||
<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><channel id="exampleChannel" publish-subscribe="true"/></programlisting>
|
||||
<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><![CDATA[<channel id="exampleChannel" publish-subscribe="true">
|
||||
<programlisting language="xml"><![CDATA[<channel id="exampleChannel" publish-subscribe="true">
|
||||
<dispatcher-policy max-messages-per-task="25"
|
||||
receive-timeout="10"
|
||||
rejection-limit="3"
|
||||
@@ -87,12 +88,12 @@
|
||||
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><![CDATA[<channel id="numberChannel" datatype="java.lang.Number"/>]]></programlisting>
|
||||
<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><![CDATA[<channel id="stringOrNumberChannel" datatype="java.lang.String,java.lang.Number"/>]]></programlisting>
|
||||
<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>
|
||||
@@ -101,16 +102,16 @@
|
||||
<para>
|
||||
To specificially create a <classname>QueueChannel</classname>, use the "queue-channel" element.
|
||||
By using this element, you can also specify the channel's capacity:
|
||||
<programlisting><queue-channel id="exampleChannel" capacity="100"/></programlisting>
|
||||
<programlisting language="xml"><queue-channel id="exampleChannel" capacity="100"/></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
To create a <classname>PriorityChannel</classname>, use the "priority-channel" element:
|
||||
<programlisting><![CDATA[<priority-channel id="exampleChannel"/>]]></programlisting>
|
||||
<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, the <classname>PriorityChannel</classname> does support the "datatype"
|
||||
attribute. The following example demonstrates both:
|
||||
<programlisting><![CDATA[<priority-channel id="exampleChannel"
|
||||
<programlisting language="xml"><![CDATA[<priority-channel id="exampleChannel"
|
||||
datatype="example.Widget" comparator="widgetComparator"/>
|
||||
]]></programlisting>
|
||||
</para>
|
||||
@@ -119,7 +120,7 @@
|
||||
more <interceptor> elements can be added as sub-elements of <channel>. Provide the "ref" attribute
|
||||
to reference any Spring-managed object that implements the <interfacename>ChannelInterceptor</interfacename>
|
||||
interface:
|
||||
<programlisting><![CDATA[<channel id="exampleChannel">
|
||||
<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
|
||||
@@ -132,13 +133,13 @@
|
||||
<para>
|
||||
To create a Message Endpoint instance, use the 'handler-endpoint' element with the 'input-channel' and 'handler'
|
||||
attributes:
|
||||
<programlisting><handler-endpoint input-channel="exampleChannel" handler="exampleHandler"/></programlisting>
|
||||
<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><handler-endpoint input-channel="exampleChannel" handler="somePojo" method="someMethod"/></programlisting>
|
||||
<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
|
||||
@@ -151,7 +152,7 @@
|
||||
'returnAddress' property at all, then it will fallback to its own 'outputChannelName' property. If
|
||||
neither is available, then a <classname>MessageHandlingException</classname> will be thrown. To configure the
|
||||
output channel when using the XML namespace, provide the 'output-channel' attribute:
|
||||
<programlisting><handler-endpoint input-channel="exampleChannel"
|
||||
<programlisting language="xml"><handler-endpoint input-channel="exampleChannel"
|
||||
handler="somePojo"
|
||||
method="someMethod"
|
||||
output-channel="replyChannel"/></programlisting>
|
||||
@@ -160,7 +161,7 @@
|
||||
Endpoints also support <interfacename>MessageSelectors</interfacename> as described in
|
||||
<xref linkend="api-messageselector"/>. To configure selectors with namespace support, simply add one or more
|
||||
<selector> sub-elements to the endpoint definition:
|
||||
<programlisting><![CDATA[<handler-endpoint id="endpoint" input-channel="channel" handler="handler">
|
||||
<programlisting language="xml"><![CDATA[<handler-endpoint id="endpoint" input-channel="channel" handler="handler">
|
||||
]]><emphasis><![CDATA[<selector ref="exampleSelector"/>]]></emphasis><![CDATA[
|
||||
</handler-endpoint>]]></programlisting>
|
||||
</para>
|
||||
@@ -170,7 +171,7 @@
|
||||
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><![CDATA[<handler-endpoint input-channel="exampleChannel" handler="exampleHandler"/>
|
||||
<programlisting language="xml"><![CDATA[<handler-endpoint input-channel="exampleChannel" handler="exampleHandler"/>
|
||||
]]><emphasis><![CDATA[<schedule period="3000"/>]]></emphasis><![CDATA[
|
||||
</handler-endpoint>]]></programlisting>
|
||||
</para>
|
||||
@@ -188,7 +189,7 @@
|
||||
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><![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[
|
||||
</handler-endpoint>]]></programlisting>
|
||||
Recall the default concurrency policy values as listed in <xref linkend="api-messagebus-concurrencypolicy"/>.
|
||||
@@ -214,12 +215,12 @@
|
||||
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><message-bus/></programlisting>
|
||||
<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><![CDATA[<message-bus error-channel="errorChannel"/>
|
||||
<programlisting language="xml"><![CDATA[<message-bus error-channel="errorChannel"/>
|
||||
|
||||
<channel id="errorChannel" publish-subscribe="true" capacity="500"/>]]></programlisting>
|
||||
When exceptions occur in an endpoint's execution of its <interfacename>MessageHandler</interfacename> callback,
|
||||
@@ -236,12 +237,12 @@
|
||||
methods will happen within the handler thread pool and not the dispatcher pool. Finally, 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><![CDATA[<message-bus dispatcher-pool-size="25" auto-create-channels="true"/>]]></programlisting>
|
||||
<programlisting language="xml"><![CDATA[<message-bus dispatcher-pool-size="25" auto-create-channels="true"/>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The type of channel that gets created automatically by the bus can be customized by using the "channel-factory"
|
||||
element on the "message-bus" definition as in the following example:
|
||||
<programlisting><![CDATA[<message-bus>
|
||||
<programlisting language="xml"><![CDATA[<message-bus>
|
||||
<channel-factory ref="channelFactoryBean"/>
|
||||
</message-bus>
|
||||
|
||||
@@ -257,7 +258,7 @@
|
||||
<para>
|
||||
The most convenient way to configure Channel Adapters is by using the namespace support. The following examples
|
||||
demonstrate the namespace-based configuration of several source and target adapters:
|
||||
<programlisting><![CDATA[
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<jms-source connection-factory="connFactory" destination="inQueue" channel="in1"/>
|
||||
|
||||
<!-- using the default "connectionFactory" reference -->
|
||||
@@ -295,7 +296,7 @@
|
||||
<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><annotation-driven/></programlisting>
|
||||
<programlisting language="xml"><annotation-driven/></programlisting>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
@@ -308,7 +309,7 @@
|
||||
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>@MessageEndpoint(input="fooChannel")
|
||||
<programlisting language="java">@MessageEndpoint(input="fooChannel")
|
||||
public class FooService {
|
||||
|
||||
@Handler
|
||||
@@ -320,7 +321,7 @@ public class FooService {
|
||||
<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>@MessageEndpoint(input="fooChannel")
|
||||
<programlisting language="java">@MessageEndpoint(input="fooChannel")
|
||||
public class FooService {
|
||||
|
||||
@Handler
|
||||
@@ -335,15 +336,15 @@ public class FooService {
|
||||
the message header's 'replyChannelName' property will be used if available, and the endpoint's default output is
|
||||
the fallback. To configure the default output for an annotation-driven endpoint, provide the 'output'
|
||||
attribute on the <interfacename>@MessageEndpoint</interfacename>.
|
||||
<programlisting>@MessageEndpoint(input="exampleChannel", output="replyChannel")</programlisting>
|
||||
<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 'pollPeriod' attribute can be provided on the <interfacename>@MessageEndpoint</interfacename>.
|
||||
<programlisting>@MessageEndpoint(input="exampleChannel", pollPeriod=3000)</programlisting>
|
||||
<programlisting language="java">@MessageEndpoint(input="exampleChannel", pollPeriod=3000)</programlisting>
|
||||
Likewise, <interfacename>@Concurrency</interfacename> provides an annotation-based equivalent of the
|
||||
<concurrency/> element:
|
||||
<programlisting>@MessageEndpoint(input="fooChannel")
|
||||
<programlisting language="java">@MessageEndpoint(input="fooChannel")
|
||||
@Concurrency(coreSize=5, maxSize=20)
|
||||
public class FooService {
|
||||
|
||||
@@ -363,7 +364,7 @@ public class FooService {
|
||||
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>@Router
|
||||
<programlisting language="java">@Router
|
||||
public MessageChannel route(Message message) {...}
|
||||
|
||||
@Router
|
||||
@@ -380,7 +381,7 @@ public List<String> route(Foo payload) {...}</programlisting>
|
||||
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 map to either a property or attribute name.
|
||||
<programlisting>@Router(property="customerType")
|
||||
<programlisting language="java">@Router(property="customerType")
|
||||
public String route(String customerType)
|
||||
|
||||
@Router(attribute="orderStatus")
|
||||
@@ -392,7 +393,7 @@ public List<String> route(OrderStatus status)</programlisting>
|
||||
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. The <interfacename>@Splitter</interfacename>
|
||||
annotation expects a 'channel' attribute that specifies the channel name to which those messages should be sent.
|
||||
<programlisting>@Splitter(channel="exampleChannel")
|
||||
<programlisting language="java">@Splitter(channel="exampleChannel")
|
||||
List<LineItem> extractItems(Order order) {
|
||||
return order.getItems()
|
||||
}</programlisting>
|
||||
@@ -401,7 +402,7 @@ List<LineItem> extractItems(Order order) {
|
||||
The <interfacename>@Publisher</interfacename> annotation is a convenience 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><![CDATA[@Publisher(channel="fooChannel")
|
||||
<programlisting language="java"><![CDATA[@Publisher(channel="fooChannel")
|
||||
public String foo() {
|
||||
return "bar";
|
||||
}]]></programlisting>
|
||||
@@ -410,7 +411,7 @@ public String foo() {
|
||||
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><![CDATA[@Subscriber(channel="fooChannel")
|
||||
<programlisting language="java"><![CDATA[@Subscriber(channel="fooChannel")
|
||||
public void log(String foo) {
|
||||
System.out.println(foo);
|
||||
}]]></programlisting>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?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="api">
|
||||
<title>The Core API</title>
|
||||
|
||||
@@ -9,7 +10,7 @@
|
||||
be provided as the payload, and each <interfacename>Message</interfacename> also includes a header containing
|
||||
user-extensible properties as key-value pairs. Here is the definition of the
|
||||
<interfacename>Message</interfacename> interface:
|
||||
<programlisting>public interface Message<T> {
|
||||
<programlisting language="java">public interface Message<T> {
|
||||
Object getId();
|
||||
MessageHeader getHeader();
|
||||
T getPayload();
|
||||
@@ -70,7 +71,7 @@
|
||||
<para>
|
||||
The base implementation of the <interfacename>Message</interfacename> interface is
|
||||
<classname>GenericMessage<T></classname>, and it provides three constructors:
|
||||
<programlisting>new GenericMessage<T>(Object id, T payload);
|
||||
<programlisting language="java">new GenericMessage<T>(Object id, T payload);
|
||||
new GenericMessage<T>(T payload);
|
||||
new GenericMessage<T>(T payload, MessageHeader headerToCopy)</programlisting>
|
||||
When no id is provided, a random unique id will be generated. The constructor that accepts a
|
||||
@@ -82,7 +83,7 @@ new GenericMessage<T>(T payload, MessageHeader headerToCopy)</programlisti
|
||||
<para>
|
||||
The <classname>MessagePriority</classname> is only considered when using a <classname>PriorityChannel</classname>
|
||||
(as described in the next section). It is defined as an <emphasis>enum</emphasis> with five possible values:
|
||||
<programlisting>public enum MessagePriority {
|
||||
<programlisting language="java">public enum MessagePriority {
|
||||
HIGHEST,
|
||||
HIGH,
|
||||
NORMAL,
|
||||
@@ -107,7 +108,7 @@ new GenericMessage<T>(T payload, MessageHeader headerToCopy)</programlisti
|
||||
While the <interfacename>Message</interfacename> plays the crucial role of encapsulating data, it is the
|
||||
<interfacename>MessageChannel</interfacename> that decouples message producers from message consumers.
|
||||
Spring Integration's <interfacename>MessageChannel</interfacename> interface is defined as follows.
|
||||
<programlisting><![CDATA[public interface MessageChannel {
|
||||
<programlisting language="java"><![CDATA[public interface MessageChannel {
|
||||
String getName();
|
||||
void setName(String name);
|
||||
DispatcherPolicy getDispatcherPolicy();
|
||||
@@ -123,7 +124,7 @@ new GenericMessage<T>(T payload, MessageHeader headerToCopy)</programlisti
|
||||
receiving a message, the return value will be <emphasis>null</emphasis> in the case of a timeout or interrupt.
|
||||
The <classname>QueueChannel</classname> implementation wraps a queue. It provides a no-argument constructor as
|
||||
well as a constructor that accepts the queue capacity:
|
||||
<programlisting>public QueueChannel(int capacity)</programlisting>
|
||||
<programlisting language="java">public QueueChannel(int capacity)</programlisting>
|
||||
Specifying a capacity of 0 will create a "direct-handoff" channel where a sender will block until the channel's
|
||||
<methodname>receive()</methodname> method is called. Otherwise a channel that has not reached its capacity limit
|
||||
will store messages in its internal queue, and the <methodname>send()</methodname> method will return immediately
|
||||
@@ -148,14 +149,14 @@ new GenericMessage<T>(T payload, MessageHeader headerToCopy)</programlisti
|
||||
<interfacename>MessageChannels</interfacename>, those channels provide an opportunity for intercepting
|
||||
the send and receive operations. The <interfacename>ChannelInterceptor</interfacename> strategy interface
|
||||
provides methods for each of those operations:
|
||||
<programlisting><![CDATA[public interface ChannelInterceptor {
|
||||
<programlisting language="java"><![CDATA[public interface ChannelInterceptor {
|
||||
boolean preSend(Message<?> message, MessageChannel channel);
|
||||
void postSend(Message<?> message, MessageChannel channel, boolean sent);
|
||||
boolean preReceive(MessageChannel channel);
|
||||
void postReceive(Message<?> message, MessageChannel channel);
|
||||
}]]></programlisting>
|
||||
After implementing the interface, registering the interceptor with a channel is just a matter of calling:
|
||||
<programlisting>channel.addInterceptor(someChannelInterceptor);</programlisting>
|
||||
<programlisting language="java">channel.addInterceptor(someChannelInterceptor);</programlisting>
|
||||
The methods that return a <literal>boolean</literal> value can return '<literal>false</literal>' to prevent the
|
||||
send or receive operation from proceeding (send would return 'false' and receive would return 'null').
|
||||
</para>
|
||||
@@ -165,7 +166,7 @@ new GenericMessage<T>(T payload, MessageHeader headerToCopy)</programlisti
|
||||
methods (the <literal>void</literal> methods are empty, and the <literal>boolean</literal> methods return
|
||||
<literal>true</literal>). Therefore, it is often easiest to extend that class and just implement the method(s)
|
||||
that you need as in the following example.
|
||||
<programlisting><![CDATA[public class CountingChannelInterceptor extends ChannelInterceptorAdapter {
|
||||
<programlisting language="java"><![CDATA[public class CountingChannelInterceptor extends ChannelInterceptorAdapter {
|
||||
|
||||
private final AtomicInteger sendCount = new AtomicInteger();
|
||||
|
||||
@@ -183,7 +184,7 @@ new GenericMessage<T>(T payload, MessageHeader headerToCopy)</programlisti
|
||||
<para>
|
||||
So far we have seen that generic message objects are sent-to and received-from simple channel objects. Here is
|
||||
Spring Integration's callback interface for handling the <interfacename>Messages</interfacename>:
|
||||
<programlisting>public interface MessageHandler {
|
||||
<programlisting language="java">public interface MessageHandler {
|
||||
Message<?> handle(Message<?> message);
|
||||
}</programlisting>
|
||||
The handler plays an important role, since it is typically responsible for translating between the generic
|
||||
@@ -210,7 +211,7 @@ new GenericMessage<T>(T payload, MessageHeader headerToCopy)</programlisti
|
||||
by delegating to other strategies. One of its fundamental responsibilities is to manage registration of the
|
||||
<interfacename>MessageChannels</interfacename> and <interfacename>MessageHandlers</interfacename>. It provides
|
||||
the following methods:
|
||||
<programlisting>public void registerChannel(String name, MessageChannel channel)
|
||||
<programlisting language="java">public void registerChannel(String name, MessageChannel channel)
|
||||
|
||||
public void registerHandler(String name, MessageHandler handler,
|
||||
Subscription subscription)
|
||||
@@ -401,7 +402,7 @@ public void registerHandler(String name, MessageHandler handler,
|
||||
<interfacename>MessageHandler</interfacename> along with its metadata. In fact, the
|
||||
<interfacename>MessageEndpoint</interfacename> does extend the <interfacename>MessageHandler</interfacename>
|
||||
interface.
|
||||
<programlisting>public interface MessageEndpoint extends MessageHandler {
|
||||
<programlisting language="java">public interface MessageEndpoint extends MessageHandler {
|
||||
String getName();
|
||||
Subscription getSubscription();
|
||||
ConcurrencyPolicy getConcurrencyPolicy();
|
||||
@@ -421,7 +422,7 @@ public void registerHandler(String name, MessageHandler handler,
|
||||
is hosted by an endpoint and thereby subscribed to a channel. Often it is necessary to provide additional
|
||||
<emphasis>dynamic</emphasis> logic to determine what messages the handler should receive. The
|
||||
<interfacename>MessageSelector</interfacename> strategy interface fulfills that role.
|
||||
<programlisting><![CDATA[public interface MessageSelector {
|
||||
<programlisting language="java"><![CDATA[public interface MessageSelector {
|
||||
boolean accept(Message<?> message);
|
||||
}]]></programlisting>
|
||||
A <interfacename>MessageEndpoint</interfacename> can be configured with zero or more selectors, and will only
|
||||
@@ -429,7 +430,7 @@ public void registerHandler(String name, MessageHandler handler,
|
||||
common selector implementations are provided. For example, the <classname>PayloadTypeSelector</classname>
|
||||
provides similar functionality to Datatype Channels (as described in <xref linkend="namespace-channel"/>)
|
||||
except that in this case the type-matching can be done by the endpoint rather than the channel.
|
||||
<programlisting><![CDATA[PayloadTypeSelector selector = new PayloadTypeSelector(String.class, Integer.class);
|
||||
<programlisting language="java"><![CDATA[PayloadTypeSelector selector = new PayloadTypeSelector(String.class, Integer.class);
|
||||
assertTrue(selector.accept(new StringMessage("example")));
|
||||
assertTrue(selector.accept(new GenericMessage<Integer>(123)));
|
||||
assertFalse(selector.accept(new GenericMessage<SomeObject>(someObject)));
|
||||
@@ -442,17 +443,17 @@ assertFalse(selector.accept(new GenericMessage<SomeObject>(someObject)));
|
||||
Essentially, using a selector provides <emphasis>reactive</emphasis> routing whereas the Datatype Channel
|
||||
and Message Router provide <emphasis>proactive</emphasis> routing. However, selectors accommodate additional
|
||||
uses. For example, the <interfacename>MessageChannel</interfacename>'s 'purge' method accepts a selector:
|
||||
<programlisting>channel.purge(someSelector);</programlisting>
|
||||
<programlisting language="java">channel.purge(someSelector);</programlisting>
|
||||
There is even a <classname>ChannelPurger</classname> utility class whose purge operation is a good candidate for
|
||||
Spring's JMX support:
|
||||
<programlisting>ChannelPurger purger = new ChannelPurger(new ExampleMessageSelector(), channel);
|
||||
<programlisting language="java">ChannelPurger purger = new ChannelPurger(new ExampleMessageSelector(), channel);
|
||||
purger.purge();</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Implementations of <interfacename>MessageSelector</interfacename> might provide opportunities for reuse on
|
||||
channels in addition to endpoints. For that reason, Spring Integration provides a simple selector-wrapping
|
||||
<interfacename>ChannelInterceptor</interfacename> that accepts one or more selectors in its constructor.
|
||||
<programlisting>MessageSelectingInterceptor interceptor =
|
||||
<programlisting language="java">MessageSelectingInterceptor interceptor =
|
||||
new MessageSelectingInterceptor(selector1, selector2);
|
||||
channel.addInterceptor(interceptor);</programlisting>
|
||||
</para>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?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="overview">
|
||||
<title>Spring Integration Overview</title>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?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="resources">
|
||||
<title>Additional Resources</title>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?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="samples">
|
||||
<title>Spring Integration Samples</title>
|
||||
|
||||
@@ -29,7 +30,7 @@
|
||||
</para>
|
||||
<para>
|
||||
Here is the XML configuration:
|
||||
<programlisting><![CDATA[<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
<programlisting language="xml"><![CDATA[<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
@@ -64,7 +65,7 @@
|
||||
the <interfacename>@MessageEndpoint</interfacename> annotation. That annotation extends Spring's
|
||||
"stereotype" annotations (by relying on the @Component meta-annotation), and so all classes carrying the
|
||||
endpoint annotation are capable of being detected by the component-scanner.
|
||||
<programlisting><![CDATA[@MessageEndpoint(input="orders")
|
||||
<programlisting language="java"><![CDATA[@MessageEndpoint(input="orders")
|
||||
public class OrderSplitter {
|
||||
|
||||
@Splitter(channel="drinks")
|
||||
@@ -72,7 +73,7 @@ public class OrderSplitter {
|
||||
return order.getDrinks();
|
||||
}
|
||||
}]]></programlisting>
|
||||
<programlisting><![CDATA[@MessageEndpoint(input="drinks")
|
||||
<programlisting language="java"><![CDATA[@MessageEndpoint(input="drinks")
|
||||
public class DrinkRouter {
|
||||
|
||||
@Router
|
||||
@@ -85,7 +86,7 @@ public class DrinkRouter {
|
||||
Now turning back to the XML, you see that there are two <endpoint> elements. Each of these is delegating
|
||||
to the same <classname>Barista</classname> instance but different methods. The 'barista' could have been
|
||||
defined in the XML, but instead the <interfacename>@Component</interfacename> annotation is applied:
|
||||
<programlisting><![CDATA[@Component
|
||||
<programlisting language="java"><![CDATA[@Component
|
||||
public class Barista {
|
||||
|
||||
private long hotDrinkDelay = 1000;
|
||||
@@ -127,7 +128,7 @@ public class Barista {
|
||||
As you can see from the code excerpt above, the barista methods have different delays. This simulates work being
|
||||
completed at different rates. When the <classname>CafeDemo</classname> 'main' method runs, it will loop 100
|
||||
times sending a single hot drink and a single cold drink each time.
|
||||
<programlisting><![CDATA[public static void main(String[] args) {
|
||||
<programlisting language="java"><![CDATA[public static void main(String[] args) {
|
||||
AbstractApplicationContext context = null;
|
||||
if(args.length > 0) {
|
||||
context = new FileSystemXmlApplicationContext(args);
|
||||
@@ -163,7 +164,7 @@ public class Barista {
|
||||
However, by configuring the endpoint concurrency, you can dramatically change the results. For example, on my
|
||||
machine, the following single modification causes all 100 hot drinks to be prepared before the 4th cold drink is
|
||||
ready:
|
||||
<programlisting><![CDATA[<handler-endpoint input-channel="coldDrinks" handler="barista" method="prepareColdDrink"/>
|
||||
<programlisting language="xml"><![CDATA[<handler-endpoint input-channel="coldDrinks" handler="barista" method="prepareColdDrink"/>
|
||||
|
||||
<handler-endpoint input-channel="hotDrinks" handler="barista" method="prepareHotDrink">
|
||||
]]><emphasis><![CDATA[<concurrency core="25" max="50"/>]]></emphasis><![CDATA[
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
<?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" [
|
||||
<!ENTITY overview SYSTEM "overview.xml">
|
||||
<!ENTITY core-api SYSTEM "core-api.xml">
|
||||
<!ENTITY adapters SYSTEM "adapters.xml">
|
||||
<!ENTITY configuration SYSTEM "configuration.xml">
|
||||
<!ENTITY samples SYSTEM "samples.xml">
|
||||
<!ENTITY resources SYSTEM "resources.xml">
|
||||
]>
|
||||
<book>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<book xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<bookinfo>
|
||||
<title>Spring Integration Reference Manual</title>
|
||||
|
||||
@@ -40,11 +32,11 @@
|
||||
|
||||
<toc></toc>
|
||||
|
||||
&overview;
|
||||
&core-api;
|
||||
&adapters;
|
||||
&configuration;
|
||||
&samples;
|
||||
&resources;
|
||||
<xi:include href="./overview.xml"/>
|
||||
<xi:include href="./core-api.xml"/>
|
||||
<xi:include href="./adapters.xml"/>
|
||||
<xi:include href="./configuration.xml"/>
|
||||
<xi:include href="./samples.xml"/>
|
||||
<xi:include href="./resources.xml"/>
|
||||
|
||||
</book>
|
||||
Reference in New Issue
Block a user