Files
spring-integration/spring-integration-reference/src/namespaces.xml
2008-11-03 01:51:38 +00:00

202 lines
13 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="namespaces">
<title>Namespace Support</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>
<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>&gt;</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>&lt;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 (&lt;beans:bean ... /&gt;). 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 id="namespace-messagebus">
<title>Configuring the Message Bus</title>
<para>
The Message Bus plays a central role, but 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.
The Message Bus can be configured with a single empty element:
<programlisting language="xml">&lt;message-bus/&gt;</programlisting>
</para>
<para>
The Message Bus provides default error handling for its components in the form of a configurable error channel,
and it will first check for a channel bean named 'errorChannel' within the context:
<programlisting language="xml"><![CDATA[<message-bus/>
<channel id="errorChannel" capacity="500"/>]]></programlisting>
When exceptions occur in a scheduled poller task's execution, those exceptions will be wrapped in
<classname>ErrorMessages</classname> and sent to the 'errorChannel' by default. 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. However, since most of the errors will already have been wrapped in
<classname>MessageDeliveryException</classname> or <classname>MessageHandlingException</classname>,
the <classname>ErrorMessageExceptionTypeRouter</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 reference to a <interfacename>TaskScheduler</interfacename> implementation.
If not provided, a default will be created. The scheduler is responsible for managing the pollers.
<programlisting language="xml"><![CDATA[<message-bus task-scheduler="someScheduler"/>]]></programlisting>
When the endpoints are concurrency-enabled with their own 'taskExecutor' reference, the invocation of the handling
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, then it will be invoked in the dispatcher's thread
(with the exception of subscribable channels where the subscribers may be invoked directly).
</para>
</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. 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 you want to configure a POJO reference from the "ref" attribute
of a &lt;service-activator/&gt; element, it is sufficient to provide the method-level annotations.
</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 {
@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 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&lt;String, Object&gt; headerMap) {
...
}
}</programlisting>
</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
the such an endpoint's output channel will be used if available, and the message header's REPLY_CHANNEL value
will be the fallback.
</para>
</section>
</appendix>