303 lines
20 KiB
XML
303 lines
20 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">
|
|
<appendix id="configuration">
|
|
<title>Configuration</title>
|
|
<section id="configuration-introduction">
|
|
<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 of course always an option, but we expect that most users will choose one
|
|
of the higher-level options, or a combination of the namespace-based and annotation-driven configuration.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="configuration-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 core 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>
|
|
<para>
|
|
Many other namespaces are provided within the Spring Integration distribution. In fact, each adapter type (JMS,
|
|
File, etc.) that provides namespace support defines its elements within a separate schema. In order to use these
|
|
elements, simply add the necessary namespaces with an "xmlns" entry and the corresponding "schemaLocation" mapping.
|
|
For example, the following root element shows several of these namespace declarations:
|
|
<programlisting language="xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xmlns:integration="http://www.springframework.org/schema/integration"
|
|
xmlns:file="http://www.springframework.org/schema/integration/file"
|
|
xmlns:jms="http://www.springframework.org/schema/integration/jms"
|
|
xmlns:mail="http://www.springframework.org/schema/integration/mail"
|
|
xmlns:rmi="http://www.springframework.org/schema/integration/rmi"
|
|
xmlns:ws="http://www.springframework.org/schema/integration/ws"
|
|
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
|
|
http://www.springframework.org/schema/integration/file
|
|
http://www.springframework.org/schema/integration/file/spring-integration-file-1.0.xsd
|
|
http://www.springframework.org/schema/integration/jms
|
|
http://www.springframework.org/schema/integration/jms/spring-integration-jms-1.0.xsd
|
|
http://www.springframework.org/schema/integration/mail
|
|
http://www.springframework.org/schema/integration/mail/spring-integration-mail-1.0.xsd
|
|
http://www.springframework.org/schema/integration/rmi
|
|
http://www.springframework.org/schema/integration/rmi/spring-integration-rmi-1.0.xsd
|
|
http://www.springframework.org/schema/integration/ws
|
|
http://www.springframework.org/schema/integration/ws/spring-integration-ws-1.0.xsd">
|
|
...
|
|
</beans>]]></programlisting>
|
|
The reference manual provides specific examples of the various elements in their corresponding chapters. Here, the
|
|
main thing to recognize is the consistency of the naming for each namespace URI and schema location.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="namespace-taskscheduler">
|
|
<title>Configuring the Task Scheduler</title>
|
|
<para>
|
|
In Spring Integration, the ApplicationContext plays the central role of a Message Bus, and there are only a
|
|
couple configuration options to be aware of. First, you may want to control the central TaskScheduler instance.
|
|
You can do so by providing a single bean with the name "taskScheduler". This is also defined as a constant:
|
|
<programlisting><![CDATA[ IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME ]]></programlisting>
|
|
By default Spring Integration uses the <classname>SimpleTaskScheduler</classname> implementation. That in turn
|
|
just delegates to any instance of Spring's <interfacename>TaskExecutor</interfacename> abstraction. Therefore,
|
|
it's rather trivial to supply your own configuration. The "taskScheduler" bean is then responsible for managing
|
|
all pollers. The TaskScheduler will startup automatically by default. If you provide your own instance of
|
|
SimpleTaskScheduler however, you can set the 'autoStartup' property to <emphasis>false</emphasis> instead.
|
|
</para>
|
|
<para>
|
|
When Polling Consumers provide an explicit task-executor reference in their configuration, the invocation of
|
|
the handler methods will happen within that executor's thread pool and not the main scheduler pool. However,
|
|
when no task-executor is provided for an endpoint's poller, it will be invoked by one of the main scheduler's
|
|
threads.
|
|
<note>
|
|
An endpoint is a <emphasis>Polling Consumer</emphasis> if its input channel is one of the queue-based
|
|
(i.e. pollable) channels. On the other hand, <emphasis>Event Driven Consumers</emphasis> are those whose
|
|
input channels have dispatchers instead of queues (i.e. they are subscribable). Such endpoints have no
|
|
poller configuration since their handlers will be invoked directly.
|
|
</note>
|
|
<para>
|
|
The next section will describe what happens if Exceptions occur within the asynchronous invocations.
|
|
</para>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="namespace-errorhandler">
|
|
<title>Error Handling</title>
|
|
<para>
|
|
As described in the overview at the very beginning of this manual, one of the main motivations behind a
|
|
Message-oriented framework like Spring Integration is to promote loose-coupling between components. The
|
|
Message Channel plays an important role in that producers and consumers do not have to know about each
|
|
other. However, the advantages also have some drawbacks. Some things become more complicated in a very
|
|
loosely coupled environment, and one example is error handling.
|
|
</para>
|
|
<para>
|
|
When sending a Message to a channel, the component that ultimately handles that Message may or may not
|
|
be operating within the same thread as the sender. If using a simple default DirectChannel (with the
|
|
<channel> element that has no <queue> sub-element and no 'task-executor' attribute), the
|
|
Message-handling will occur in the same thread as the Message-sending. In that case, if an Exception
|
|
is thrown, it can be caught by the sender (or it may propagate past the sender if it is an uncaught
|
|
RuntimeException). So far, everything is fine. This is the same behavior as an Exception-throwing
|
|
operation in a normal call stack. However, when adding the asynchronous aspect, things become much
|
|
more complicated. For instance, if the 'channel' element <emphasis>does</emphasis> provide a 'queue'
|
|
sub-element, then the component that handles the Message <emphasis>will</emphasis> be operating in a
|
|
different thread than the sender. The sender may have dropped the Message into the channel and moved
|
|
on to other things. There is no way for the Exception to be thrown directly back to that sender using
|
|
standard Exception throwing techniques. Instead, to handle errors for asynchronous processes requires
|
|
an asynchronous error-handling mechanism as well.
|
|
</para>
|
|
<para>
|
|
Spring Integration supports error handling for its components by publishing errors to a Message Channel.
|
|
Specifically, the Exception will become the payload of a Spring Integration Message. That Message will
|
|
then be sent to a Message Channel that is resolved in a way that is similar to the 'replyChannel'
|
|
resolution. First, if the request Message being handled at the time the Exception occurred contains
|
|
an 'errorChannel' header (the header name is defined in the constant: MessageHeaders.ERROR_CHANNEL),
|
|
the ErrorMessage will be sent to that channel. Otherwise, the error handler will send to a "global"
|
|
channel whose bean name is "errorChannel" (this is also defined as a constant:
|
|
IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME).
|
|
</para>
|
|
<para>
|
|
Whenever relying on Spring Integration's XML namespace support, a default "errorChannel" bean will be
|
|
created behind the scenes. However, you can just as easily define your own if you want to control the
|
|
settings.
|
|
<programlisting language="xml"><![CDATA[ <channel id="errorChannel">
|
|
<queue capacity="500"/>
|
|
</channel>]]></programlisting>
|
|
<note>
|
|
The default "errorChannel" is a PublishSubscribeChannel.
|
|
</note>
|
|
</para>
|
|
<para>
|
|
The most important thing to understand here is that the messaging-based error handling will only apply
|
|
to Exceptions that are thrown by a Spring Integration task that is executing within a TaskExecutor.
|
|
This does <emphasis>not</emphasis> apply to Exceptions thrown by a handler that is operating within
|
|
the same thread as the sender (e.g. through a DirectChannel as described above).
|
|
</para>
|
|
<note>
|
|
When Exceptions occur in a scheduled poller task's execution, those exceptions will be wrapped in
|
|
<classname>ErrorMessages</classname> and sent to the 'errorChannel' as well.
|
|
</note>
|
|
<para>
|
|
To enable global error handling, simply register a handler on that channel. For example, you can configure
|
|
Spring Integration's <classname>ErrorMessageExceptionTypeRouter</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.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="annotations">
|
|
<title>Annotation Support</title>
|
|
<para>
|
|
In addition to the XML namespace support for configuring Message Endpoints, it is also possible to use
|
|
annotations. First, Spring Integration provides the class-level <interfacename>@MessageEndpoint</interfacename>
|
|
as a <emphasis>stereotype</emphasis> annotation meaning that is itself annotated with Spring's @Component
|
|
annotation and therefore is recognized automatically as a bean definition when using Spring component-scanning.
|
|
</para>
|
|
<para>
|
|
Even more importantly are the various Method-level annotations that indicate the annotated method is capable of
|
|
handling a message. The following example demonstrates both:
|
|
<programlisting language="java">@MessageEndpoint
|
|
public class FooService {
|
|
|
|
@ServiceActivator
|
|
public void processMessage(Message message) {
|
|
...
|
|
}
|
|
}</programlisting>
|
|
</para>
|
|
<para>
|
|
Exactly what it means for the method to "handle" the Message depends on the particular annotation. The following
|
|
are available with Spring Integration, and the behavior of each is described in its own chapter or section within
|
|
this reference: @Transformer, @Router, @Splitter, @Aggregator, @ServiceActivator, and @ChannelAdapter.
|
|
</para>
|
|
<note>
|
|
The @MessageEndpoint is not required if using XML configuration in combination with annotations. If you want to
|
|
configure a POJO reference from the "ref" attribute of a <service-activator/> element, it is sufficient to
|
|
provide the method-level annotations. In that case, the annotation prevents ambiguity even when no "method"
|
|
attribute exists on the <service-activator/> element.
|
|
</note>
|
|
<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">public class FooService {
|
|
|
|
@ServiceActivator
|
|
public void bar(<emphasis>Foo foo</emphasis>) {
|
|
...
|
|
}
|
|
|
|
}</programlisting>
|
|
</para>
|
|
<para>
|
|
When the method parameter should be mapped from a value in the <classname>MessageHeaders</classname>, another
|
|
option is to use the parameter-level <interfacename>@Header</interfacename> annotation. In general, methods
|
|
annotated with the Spring Integration annotations can either accept the <classname>Message</classname> itself, the
|
|
message payload, or a header value (with @Header) as the parameter. In fact, the method can accept a combination,
|
|
such as:
|
|
<programlisting language="java">public class FooService {
|
|
|
|
@ServiceActivator
|
|
public void bar(String payload, @Header("x") int valueX, @Header("y") int valueY) {
|
|
...
|
|
}
|
|
|
|
}</programlisting>
|
|
There is also a @Headers annotation that provides all of the Message headers as a Map:
|
|
<programlisting language="java">public class FooService {
|
|
|
|
@ServiceActivator
|
|
public void bar(String payload, @Headers Map<String, Object> headerMap) {
|
|
...
|
|
}
|
|
|
|
}</programlisting>
|
|
<tip>
|
|
A Map-typed argument does not strictly require the use of the @Headers annotation. In other words
|
|
the following is also valid: <programlisting language="java">public void bar(String payload, Map<String, Object> headerMap)</programlisting>
|
|
However this can lead to unresolvable ambiguities if the payload is itself a Map. For that reason, we
|
|
highly recommend using the annotation whenever expecting the headers. For a much more detailed
|
|
description, see the javadoc for <classname>MethodParameterMessageMapper</classname>.
|
|
</tip>
|
|
</para>
|
|
<para>
|
|
For several of these annotations, when a Message-handling 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 such an endpoint's output channel will be used if available, and the REPLY_CHANNEL message header value
|
|
will be used as a fallback.
|
|
</para>
|
|
<tip>
|
|
The combination of output channels on endpoints and the reply channel message header enables a pipeline approach
|
|
where multiple components have an output channel, and the final component simply allows the reply message to be
|
|
forwarded to the reply channel as specified in the original request message. In other words, the final component
|
|
depends on the information provided by the original sender and can dynamically support any number of clients as a
|
|
result. This is an example of <ulink url="http://eaipatterns.com/ReturnAddress.html">Return Address</ulink>.
|
|
</tip>
|
|
<para>
|
|
In addition to the examples shown here, these annotations also support inputChannel and outputChannel properties.
|
|
<programlisting language="java">public class FooService {
|
|
|
|
@ServiceActivator(inputChannel="input", outputChannel="output")
|
|
public void bar(String payload, @Headers Map<String, Object> headerMap) {
|
|
...
|
|
}
|
|
|
|
}</programlisting>
|
|
That provides a pure annotation-driven alternative to the XML configuration. However, it is generally recommended
|
|
to use XML for the endpoints, since it is easier to keep track of the overall configuration in a single, external
|
|
location (and besides the namespace-based XML configuration is not very verbose). If you do prefer to provide
|
|
channels with the annotations however, you just need to enable a BeanPostProcessor. The following element should
|
|
be added: <programlisting language="xml"><![CDATA[ <annotation-config/> ]]></programlisting>
|
|
<note>
|
|
When configuring the "inputChannel" and "outputChannel" with annotations, the "inputChannel"
|
|
<emphasis>must</emphasis> be a reference to a <interfacename>SubscribableChannel</interfacename> instance.
|
|
Otherwise, it would be necessary to also provide the full poller configuration via annotations, and those
|
|
settings (e.g. the trigger for scheduling the poller) should be externalized rather than hard-coded within
|
|
an annotation. If the input channel that you want to receive Messages from is indeed a
|
|
<interfacename>PollableChannel</interfacename> instance, one option to consider is the Messaging Bridge.
|
|
Spring Integration's "bridge" element can be used to connect a PollableChannel directly to a
|
|
SubscribableChannel. Then, the polling metadata is externally configured, but the annotation option is
|
|
still available. For more detail see <xref linkend="bridge"/>.
|
|
</note>
|
|
</para>
|
|
</section>
|
|
|
|
</appendix> |