This commit updates Spring Integration to depend upon Spring 4, making use of the message types that have moved from Spring Integration into Spring's new spring-messaging module. The default message converter no longer supports conversion of a message that is null, throwing an IllegalArgumentException if an attempt is made to convert null. Furthermore, GenericMessagingTemplate does not support sending null, again throwing an IllegalArgumentException. Previously, MessagingTemplate had no-oped an attempt to send null. ConcurrentAggregatorTests and AggregatorTests both had a single test that was specifically testing the behaviour of an aggregator that returns null for its message. These tests have been removed. CorrelatingMessageHandlerTests have been updated to specify some additional behaviour for its mocks so that null messages are not returned. These are the only functional changes that have been made. All other changes are simply for moving to the repackaged and/or renamed types. In the move to being part of core Spring, a number of constants and header accessor methods have moved from MessageHeaders to MessageHeaderAccessor. This commit continues this pattern for the enterprise integration headers that are specific to Spring Integration. A new class, EiMessageHeaderAccessor, has been created. This class provides constants and methods for working with SI-specific headers. The main code and tests have been updated to use this new class.
103 lines
6.5 KiB
XML
103 lines
6.5 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<section xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="service-activator"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>Service Activator</title>
|
|
|
|
<section id="service-activator-introduction">
|
|
<title>Introduction</title>
|
|
<para>
|
|
The Service Activator is the endpoint type for connecting any Spring-managed Object to an input channel so that
|
|
it may play the role of a service. If the service produces output, it may also be connected to an output channel.
|
|
Alternatively, an output producing service may be located at the end of a processing pipeline or message flow in
|
|
which case, the inbound Message's "replyChannel" header can be used. This is the default behavior if no output
|
|
channel is defined, and as with most of the configuration options you'll see here, the same behavior actually
|
|
applies for most of the other components we have seen.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="service-activator-namespace">
|
|
<title>Configuring Service Activator</title>
|
|
<para>
|
|
To create a Service Activator, use the 'service-activator' element with the 'input-channel' and 'ref' attributes:
|
|
<programlisting language="xml"><int:service-activator input-channel="exampleChannel" ref="exampleHandler"/></programlisting>
|
|
</para>
|
|
<para>
|
|
The configuration above assumes that "exampleHandler" either contains a single method annotated with the
|
|
@ServiceActivator annotation or that it contains only one public method at all. To delegate to an explicitly
|
|
defined method of any object, simply add the "method" attribute.
|
|
<programlisting language="xml"><int:service-activator input-channel="exampleChannel" ref="somePojo" method="someMethod"/></programlisting>
|
|
</para>
|
|
<para>
|
|
In either case, when the service 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"><int:service-activator input-channel="exampleChannel" output-channel="replyChannel"
|
|
ref="somePojo" method="someMethod"/></programlisting>
|
|
If no "output-channel" is available, it will then check the Message's <literal>replyChannel</literal> header
|
|
value. If that value is available, it will then check its type. If it is a
|
|
<interfacename>MessageChannel</interfacename>, 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 name to a channel instance.
|
|
If the channel cannot be resolved, then a <classname>DestinationResolutionException</classname> will be thrown.
|
|
It it can be resolved, the Message will be sent there. This is the technique used for Request Reply messaging
|
|
in Spring Integration, and it is also an example of the Return Address pattern.
|
|
</para>
|
|
<para>
|
|
The argument in the service method could be either a Message or an arbitrary type. If the latter, then it will
|
|
be assumed that it is a Message payload, which will be extracted from the message and injected into such service
|
|
method. This is generally the recommended approach as it follows and promotes a POJO model when working with Spring
|
|
Integration. Arguments may also have @Header or @Headers annotations as described in <xref linkend="annotations"/>
|
|
</para>
|
|
<note>
|
|
The service method is not required to have any arguments at all, which means you
|
|
can implement event-style Service Activators, where all you care about is an invocation of the service method,
|
|
not worrying about the contents of the message. Think of it as a NULL JMS message. An example use-case for such an
|
|
implementation could be a simple counter/monitor of messages deposited on the input channel.
|
|
</note>
|
|
<para>
|
|
Using a "ref" attribute is generally recommended if the custom Service Activator handler implementation can be reused
|
|
in other <code><service-activator></code> definitions. However if the custom Service Activator handler implementation
|
|
is only used within a single definition of the <code><service-activator></code>, you can provide an inner bean definition:
|
|
<programlisting language="xml"><![CDATA[<int:service-activator id="exampleServiceActivator" input-channel="inChannel"
|
|
output-channel = "outChannel" method="foo">
|
|
<beans:bean class="org.foo.ExampleServiceActivator"/>
|
|
</int:service-activator>]]></programlisting>
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Using both the "ref" attribute and an inner handler definition in the same <code><service-activator></code>
|
|
configuration is not allowed, as it creates an ambiguous condition and will result in an Exception being thrown.
|
|
</para>
|
|
</note>
|
|
|
|
<para>
|
|
<emphasis>Service Activators and the Spring Expression Language (SpEL)</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
Since Spring Integration 2.0, Service Activators can also benefit from SpEL
|
|
(http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/expressions.html).
|
|
</para>
|
|
<para>
|
|
For example, you may now invoke any bean method without pointing to the bean via a <code>ref</code> attribute or including it as an
|
|
inner bean definition. For example:
|
|
|
|
<programlisting language="xml"><![CDATA[<int:service-activator input-channel="in" output-channel="out"
|
|
expression="@accountService.processAccount(payload, headers.accountId)"/>
|
|
|
|
<bean id="accountService" class="foo.bar.Account"/>]]></programlisting>
|
|
|
|
In the above configuration instead of injecting 'accountService' using a <code>ref</code> or as an inner bean,
|
|
we are simply using SpEL's <code>@beanId</code> notation and invoking a method which takes a type compatible with Message payload. We
|
|
are also passing a header value. As you can see, any valid SpEL expression can be evaluated against any content in the Message.
|
|
For simple scenarios your <emphasis>Service Activators</emphasis> do not even have to reference a bean if all logic can be encapsulated
|
|
by such an expression.
|
|
|
|
<programlisting language="xml"><![CDATA[<int:service-activator input-channel="in" output-channel="out" expression="payload * 2"/>]]></programlisting>
|
|
In the above configuration our service logic is to simply multiply the payload value by 2, and SpEL lets us handle it relatively easy.
|
|
|
|
</para>
|
|
|
|
</section>
|
|
|
|
</section>
|