Files
spring-integration/src/reference/docbook/service-activator.xml
Andy Wilkinson 28ab8394de Build on top of Spring 4's new messaging types
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.
2013-10-08 16:42:22 -04:00

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">&lt;int:service-activator input-channel="exampleChannel" ref="exampleHandler"/&gt;</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">&lt;int:service-activator input-channel="exampleChannel" ref="somePojo" method="someMethod"/&gt;</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">&lt;int:service-activator input-channel="exampleChannel" output-channel="replyChannel"
ref="somePojo" method="someMethod"/&gt;</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>&lt;service-activator&gt;</code> definitions. However if the custom Service Activator handler implementation
is only used within a single definition of the <code>&lt;service-activator&gt;</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>&lt;service-activator&gt;</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>