Add reference docs: - Caution about using cached consumers with a specified reply dest. - Add <reply-listener/> docs. INT-2667 Polishing PR Review Comments
471 lines
30 KiB
XML
471 lines
30 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="jms"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>JMS Support</title>
|
|
<para>
|
|
Spring Integration provides Channel Adapters for receiving and sending JMS messages. There are actually two
|
|
JMS-based inbound Channel Adapters. The first uses Spring's <classname>JmsTemplate</classname> to receive based on
|
|
a polling period. The second is "message-driven" and relies upon a Spring MessageListener container. There is also
|
|
an outbound Channel Adapter which uses the <classname>JmsTemplate</classname> to convert and send a JMS Message on
|
|
demand.
|
|
</para>
|
|
<para>
|
|
As you can see from above by using <classname>JmsTemplate</classname> and <classname>MessageListener</classname> container Spring Integration relies on Spring's JMS support.
|
|
This is important to understand since most of the attributes exposed on these adapters will configure the underlying Spring's <classname>JmsTemplate</classname> and/or
|
|
<classname>MessageListener</classname> container. For more details about <classname>JmsTemplate</classname> and <classname>MessageListener</classname> container please refer to
|
|
<ulink url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jms.html">Spring JMS documentation</ulink>.
|
|
</para>
|
|
<para>
|
|
Whereas the JMS Channel Adapters are intended for unidirectional Messaging (send-only or receive-only), Spring
|
|
Integration also provides inbound and outbound JMS Gateways for request/reply operations. The inbound gateway
|
|
relies on one of Spring's MessageListener container implementations for Message-driven reception that is also
|
|
capable of sending a return value to the "reply-to" Destination as provided by the received Message. The outbound
|
|
Gateway sends a JMS Message to a "request-destination" and then receives a reply Message. The "reply-destination"
|
|
reference (or "reply-destination-name") can be configured explicitly or else the outbound gateway will use a
|
|
JMS <ulink url="http://docs.oracle.com/javaee/6/api/javax/jms/TemporaryQueue.html">TemporaryQueue</ulink>.
|
|
</para>
|
|
<para>
|
|
Prior to <emphasis>Spring Integration 2.2</emphasis>, if necessary, a <interfacename>TemporaryQueue</interfacename>
|
|
was created (and removed)
|
|
for each request/reply. Beginning with <emphasis>Spring Integration 2.2</emphasis>, the outbound gateway
|
|
can be configured to use
|
|
a <classname>MessageListener</classname> container to receive replies instead of directly
|
|
using a new (or cached) <classname>Consumer</classname> to receive the reply for each request. When so
|
|
configured, and no explicit reply destination is provided, a single <interfacename>TemporaryQueue</interfacename>
|
|
is used for each gateway instead of one for each request.
|
|
</para>
|
|
|
|
<section id="jms-inbound-channel-adapter">
|
|
<title>Inbound Channel Adapter</title>
|
|
<para>
|
|
The inbound Channel Adapter requires a reference to either a single <classname>JmsTemplate</classname>
|
|
instance or both <interfacename>ConnectionFactory</interfacename> and <interfacename>Destination</interfacename>
|
|
(a 'destinationName' can be provided in place of the 'destination' reference). The following example defines an
|
|
inbound Channel Adapter with a <classname>Destination</classname> reference.
|
|
<programlisting language="xml"><![CDATA[ <int-jms:inbound-channel-adapter id="jmsIn" destination="inQueue" channel="exampleChannel">
|
|
<int:poller fixed-rate="30000"/>
|
|
</int-jms:inbound-channel-adapter>]]></programlisting>
|
|
<tip>
|
|
Notice from the configuration that the inbound-channel-adapter is a Polling Consumer. That means that
|
|
it invokes receive() when triggered. This should only be used in situations where polling is done relatively
|
|
infrequently and timeliness is not important. For all other situations (a vast majority of JMS-based use-cases),
|
|
the <emphasis>message-driven-channel-adapter</emphasis> described below is a better option.
|
|
</tip>
|
|
<note>
|
|
All of the JMS adapters that require a reference to the ConnectionFactory will automatically look for
|
|
a bean named "connectionFactory" by default. That is why you don't see a "connection-factory" attribute
|
|
in many of the examples. However, if your JMS ConnectionFactory has a different bean name, then you will
|
|
need to provide that attribute.
|
|
</note>
|
|
</para>
|
|
<para>
|
|
If 'extract-payload' is set to true (which is the default), the received JMS Message will be passed through
|
|
the MessageConverter. When relying on the default SimpleMessageConverter, this means that the resulting Spring
|
|
Integration Message will have the JMS Message's body as its payload. A JMS TextMessage will produce a
|
|
String-based payload, a JMS BytesMessage will produce a byte array payload, and a JMS ObjectMessage's
|
|
Serializable instance will become the Spring Integration Message's payload. If instead you prefer to have
|
|
the raw JMS Message as the Spring Integration Message's payload, then set 'extract-payload' to false.
|
|
<programlisting language="xml"><![CDATA[ <int-jms:inbound-channel-adapter id="jmsIn"
|
|
destination="inQueue"
|
|
channel="exampleChannel"
|
|
extract-payload="false"/>
|
|
<int:poller fixed-rate="30000"/>
|
|
</int-jms:inbound-channel-adapter>]]></programlisting>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="jms-message-driven-channel-adapter">
|
|
<title>Message-Driven Channel Adapter</title>
|
|
<para>
|
|
The "message-driven-channel-adapter" requires a reference to either an instance of a Spring MessageListener
|
|
container (any subclass of <classname>AbstractMessageListenerContainer</classname>) or both
|
|
<interfacename>ConnectionFactory</interfacename> and <interfacename>Destination</interfacename>
|
|
(a 'destinationName' can be provided in place of the 'destination' reference). The following example defines a
|
|
message-driven Channel Adapter with a <classname>Destination</classname> reference.
|
|
<programlisting language="xml"><![CDATA[ <int-jms:message-driven-channel-adapter id="jmsIn" destination="inQueue" channel="exampleChannel"/>]]></programlisting>
|
|
<note>
|
|
The Message-Driven adapter also accepts several properties that pertain to the MessageListener container.
|
|
These values are only considered if you do not provide an actual 'container' reference. In that case,
|
|
an instance of DefaultMessageListenerContainer will be created and configured based on these properties.
|
|
For example, you can specify the "transaction-manager" reference, the "concurrent-consumers" value, and
|
|
several other property references and values. Refer to the JavaDoc and Spring Integration's JMS Schema
|
|
(spring-integration-jms.xsd) for more detail.
|
|
</note>
|
|
</para>
|
|
<para>
|
|
The 'extract-payload' property has the same effect as described above, and once again its default value
|
|
is 'true'. The poller sub-element is not applicable for a message-driven
|
|
Channel Adapter, as it will be actively invoked. For most usage scenarios, the message-driven approach is better since the Messages will
|
|
be passed along to the <interfacename>MessageChannel</interfacename> as soon as they are received from the underlying
|
|
JMS consumer.
|
|
</para>
|
|
<para>Finally, the <message-driven-channel-adapter> also accepts the 'error-channel' attribute. This
|
|
provides the same basic functionality as described in <xref linkend="gateway-proxy"/>.
|
|
<programlisting language="xml"><![CDATA[ <int-jms:message-driven-channel-adapter id="jmsIn" destination="inQueue"
|
|
channel="exampleChannel"
|
|
error-channel="exampleErrorChannel"/>
|
|
]]></programlisting>
|
|
When comparing this to the generic gateway configuration, or the JMS 'inbound-gateway' that will
|
|
be discussed below, the key difference here is that we are in a one-way flow
|
|
since this is a 'channel-adapter', not a gateway. Therefore, the flow downstream from the
|
|
'error-channel' should also be one-way. For example, it could simply send to a logging handler,
|
|
or it could be connected to a different JMS <outbound-channel-adapter> element.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="jms-outbound-channel-adapter">
|
|
<title>Outbound Channel Adapter</title>
|
|
<para>
|
|
The <classname>JmsSendingMessageHandler</classname> implements the <interfacename>MessageHandler</interfacename>
|
|
interface and is capable of converting Spring Integration <interfacename>Messages</interfacename> to JMS messages
|
|
and then sending to a JMS destination. It requires either a 'jmsTemplate' reference or both 'connectionFactory' and
|
|
'destination' references (again, the 'destinationName' may be provided in place of the 'destination'). As with the
|
|
inbound Channel Adapter, the easiest way to configure this adapter is with the namespace support. The following
|
|
configuration will produce an adapter that receives Spring Integration Messages from the "exampleChannel" and then
|
|
converts those into JMS Messages and sends them to the JMS Destination reference whose bean name is "outQueue".
|
|
<programlisting language="xml"><![CDATA[<int-jms:outbound-channel-adapter id="jmsOut" destination="outQueue" channel="exampleChannel"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
As with the inbound Channel Adapters, there is an 'extract-payload' property. However, the meaning is reversed
|
|
for the outbound adapter. Rather than applying to the JMS Message, the boolean property applies to the Spring
|
|
Integration Message payload. In other words, the decision is whether to pass the Spring Integration Message
|
|
<emphasis>itself</emphasis> as the JMS Message body or whether to pass the Spring Integration Message's
|
|
payload as the JMS Message body. The default value is once again 'true'. Therefore, if you pass a Spring
|
|
Integration Message whose payload is a String, a JMS TextMessage will be created. If on the other hand you
|
|
want to send the actual Spring Integration Message to another system via JMS, then simply set this to 'false'.
|
|
<note>
|
|
Regardless of the boolean value for payload extraction, the Spring Integration MessageHeaders will map to
|
|
JMS properties as long as you are relying on the default converter or provide a reference to another
|
|
instance of HeaderMappingMessageConverter (the same holds true for 'inbound' adapters except that in
|
|
those cases, it's the JMS properties mapping <emphasis>to</emphasis> Spring Integration MessageHeaders).
|
|
</note>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="jms-inbound-gateway">
|
|
<title>Inbound Gateway</title>
|
|
<para>
|
|
Spring Integration's message-driven JMS inbound-gateway delegates to a
|
|
<interfacename>MessageListener</interfacename> container, supports dynamically adjusting concurrent consumers,
|
|
and can also handle replies. The inbound gateway requires references to a
|
|
<interfacename>ConnectionFactory</interfacename>, and a request <interfacename>Destination</interfacename> (or
|
|
'requestDestinationName'). The following example defines a JMS "inbound-gateway" that receives from the JMS
|
|
queue referenced by the bean id "inQueue" and sends to the Spring Integration channel named "exampleChannel".
|
|
<programlisting language="xml"><![CDATA[ <int-jms:inbound-gateway id="jmsInGateway"
|
|
request-destination="inQueue"
|
|
request-channel="exampleChannel"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
Since the gateways provide request/reply behavior instead of unidirectional send <emphasis>or</emphasis>
|
|
receive, they also have two distinct properties for the "payload extraction" (as discussed above for the
|
|
Channel Adapters' 'extract-payload' setting). For an inbound-gateway, the 'extract-request-payload' property
|
|
determines whether the received JMS Message body will be extracted. If 'false', the JMS Message itself will
|
|
become the Spring Integration Message payload. The default is 'true'.
|
|
</para>
|
|
<para>
|
|
Similarly, for an inbound-gateway the 'extract-reply-payload' property applies to the Spring Integration Message
|
|
that is going to be converted into a reply JMS Message. If you want to pass the whole Spring Integration Message
|
|
(as the body of a JMS ObjectMessage) then set this to 'false'. By default, it is also 'true' such that the Spring
|
|
Integration Message <emphasis>payload</emphasis> will be converted into a JMS Message (e.g. String payload
|
|
becomes a JMS TextMessage).
|
|
</para>
|
|
<para>
|
|
As with anything else, Gateway invocation might result in error.
|
|
By default Producer will not be notified of the errors that might have occurred on the consumer side and will time out waiting for
|
|
the reply. However there might be times when you want to communicate an error condition back to the consumer,
|
|
in other words treat the Exception as a valid reply by mapping it to a Message. To accomplish this
|
|
JMS Inbound Gateway provides support for a Message Channel to which errors
|
|
can be sent for processing, potentially resulting in a reply Message payload
|
|
that conforms to some contract defining what a caller may expect as an "error"
|
|
reply. Such a channel can be configured via the <emphasis>error-channel</emphasis>
|
|
attribute.
|
|
|
|
<programlisting language="xml"><![CDATA[<int-jms:inbound-gateway request-destination="requestQueue"
|
|
request-channel="jmsinputchannel"
|
|
error-channel="errorTransformationChannel"/>
|
|
|
|
<int:transformer input-channel="exceptionTransformationChannel"
|
|
ref="exceptionTransformer" method="createErrorResponse"/>
|
|
]]></programlisting>
|
|
You might notice that this example looks very similar to that included
|
|
within <xref linkend="gateway-proxy"/>.
|
|
The same idea applies here: The <emphasis>exceptionTransformer</emphasis>
|
|
could be a simple POJO that creates error response objects, you could reference
|
|
the "nullChannel" to suppress the errors, or you could leave 'error-channel' out
|
|
to let the Exception propagate.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="jms-outbound-gateway">
|
|
<title>Outbound Gateway</title>
|
|
<para>
|
|
The outbound Gateway creates JMS Messages from Spring Integration Messages and then sends to a
|
|
'request-destination'. It will then handle the JMS reply Message either by using a selector to
|
|
receive from the 'reply-destination' that you configure, or if no 'reply-destination' is provided,
|
|
it will create JMS <interfacename>TemporaryQueue</interfacename>s.
|
|
<caution>
|
|
<para>
|
|
Using a reply-destination (or reply-destination-name), together with
|
|
a <classname>CachingConnectionFactory</classname> with <emphasis>cacheConsumers</emphasis> set to
|
|
<emphasis>true</emphasis>, can cause Out of Memory conditions. This is because each request gets a new consumer with
|
|
a new selector (selecting on the correlation-key value, or on the sent JMSMessageID when there is no correlation-key).
|
|
Given that these selectors are unique, they will remain in the cache unused after the current request completes.
|
|
</para>
|
|
<para>
|
|
If you specify a reply destination, you are advised to NOT use cached consumers. Alternatively,
|
|
consider using a <reply-listener/> as described below.
|
|
</para>
|
|
</caution>
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[ <int-jms:outbound-gateway id="jmsOutGateway"
|
|
request-destination="outQueue"
|
|
request-channel="outboundJmsRequests"
|
|
reply-channel="jmsReplies"/>]]></programlisting>
|
|
<para>
|
|
The 'outbound-gateway' payload extraction properties are inversely related to those of the
|
|
'inbound-gateway' (see the discussion above). That means that the 'extract-request-payload' property value
|
|
applies to the Spring Integration Message that is being converted into a JMS Message to be
|
|
<emphasis>sent as a request</emphasis>, and the 'extract-reply-payload' property value applies to the
|
|
JMS Message that is <emphasis>received as a reply</emphasis> and then converted into a Spring Integration
|
|
Message to be subsequently sent to the 'reply-channel' as shown in the example configuration above.
|
|
</para>
|
|
<para><emphasis><reply-listener/></emphasis></para>
|
|
<para>
|
|
<emphasis>Spring Integration 2.2</emphasis> introduced an alternative technique for handling replies.
|
|
If you add a
|
|
<code><reply-listener/></code> child element to the gateway, instead of creating a consumer for
|
|
each reply, a <classname>MessageListener</classname> container is used to receive the replies
|
|
and hand them over to the requesting thread. This provides a number of performance benefits
|
|
as well as alleviating the cached consumer memory utilization problem described in the caution
|
|
above.
|
|
</para>
|
|
<para>
|
|
When using a <reply-listener/>, instead of creating a <interfacename>TemporaryQueue</interfacename>
|
|
for each request, a single <interfacename>TemporaryQueue</interfacename> is used
|
|
(the gateway will create an additional <interfacename>TemporaryQueue</interfacename>, as
|
|
necessary, if the connection to the broker is lost and recovered).
|
|
</para>
|
|
<para>
|
|
When using a <emphasis>correlation-key</emphasis>, multiple gateways can share the same
|
|
reply destination because the listener container uses a selector that is unique
|
|
to each gateway.
|
|
</para>
|
|
<caution>
|
|
<para>
|
|
If you specify a reply listener, and specify a reply destination (or reply destination name),
|
|
but provide NO correlation key, the gateway will log a warning and fall back to pre-2.2
|
|
behavior. This is because there is no way to configure a selector in this case, thus there is
|
|
no way to avoid a reply going to a different gateway that might be configured with the
|
|
same reply destination.
|
|
</para>
|
|
<para>
|
|
Note that, in this situation, a new consumer is used for each request, and
|
|
consumers can build up in memory as described in the
|
|
caution above; therefore cached consumers should not be used in this case.
|
|
</para>
|
|
</caution>
|
|
<programlisting language="xml"><![CDATA[ <int-jms:outbound-gateway id="jmsOutGateway"
|
|
request-destination="outQueue"
|
|
request-channel="outboundJmsRequests"
|
|
reply-channel="jmsReplies">
|
|
<int-jms:reply-listener />
|
|
</int-jms-outbound-gateway>]]></programlisting>
|
|
<para>
|
|
In the above example, a reply listener with default attributes is used. The listener is
|
|
very lightweight and it is anticipated that, in most cases, only a single consumer will
|
|
be needed. However, attributes such as <emphasis>concurrent-consumers</emphasis>,
|
|
<emphasis>max-concurrent-consumers</emphasis> etc., can be added. Refer to the
|
|
schema for a complete list of supported attributes, together with the
|
|
<ulink url="http://static.springsource.org/spring/docs/current/spring-framework-reference/html/jms.html">Spring JMS documentation</ulink>
|
|
for their meanings.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="jms-header-mapping">
|
|
<title>Mapping Message Headers to/from JMS Message</title>
|
|
|
|
<para>
|
|
JMS Message can contain meta-information such as JMS API headers as well as simple properties.
|
|
You can map those to/from Spring Integration Message Headers using <classname>JmsHeaderMapper</classname>.
|
|
The JMS API headers are passed to the appropriate setter methods (e.g. setJMSReplyTo) whereas other headers will
|
|
be copied to the general properties of the JMS Message.
|
|
|
|
JMS Outbound Gateway is bootstrapped with the default implementation of <classname>JmsHeaderMapper</classname> which will map
|
|
standard JMS API Headers as well as primitive/String Message Headers. Custom header mapper could also be
|
|
provided via <code>header-mapper</code> attribute of inbound and outbound gateways.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
|
|
<section id="jms-conversion-and-marshalling">
|
|
<title>Message Conversion, Marshalling and Unmarshalling</title>
|
|
<para>
|
|
If you need to convert the message, all JMS adapters and gateways, allow you to
|
|
provide a <interfacename>MessageConverter</interfacename> via <emphasis>message-converter</emphasis> attribute. Simply provide the
|
|
bean name of an instance of <interfacename>MessageConverter</interfacename> that is available within the same
|
|
ApplicationContext.
|
|
Also, to provide some consistency with Marshaller and Unmarshaller interfaces Spring provides <interfacename>MarshallingMessageConverter</interfacename>
|
|
which you can configure with your own custom Marshallers and Unmarshallers
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[ <int-jms:inbound-gateway request-destination="requestQueue"
|
|
request-channel="inbound-gateway-channel"
|
|
message-converter="marshallingMessageConverter"/>
|
|
|
|
<bean id="marshallingMessageConverter"
|
|
class="org.springframework.jms.support.converter.MarshallingMessageConverter">
|
|
<constructor-arg>
|
|
<bean class="org.bar.SampleMarshaller"/>
|
|
</constructor-arg>
|
|
<constructor-arg>
|
|
<bean class="org.bar.SampleUnmarshaller"/>
|
|
</constructor-arg>
|
|
</bean>
|
|
]]></programlisting>
|
|
|
|
|
|
<note>
|
|
Note, however, that when you provide your own MessageConverter instance, it will still
|
|
be wrapped within the HeaderMappingMessageConverter. This means that the 'extract-request-payload'
|
|
and 'extract-reply-payload' properties may affect what actual objects are passed to your converter. The
|
|
HeaderMappingMessageConverter itself simply delegates to a target MessageConverter while also mapping the
|
|
Spring Integration MessageHeaders to JMS Message properties and vice-versa.
|
|
</note>
|
|
|
|
</section>
|
|
|
|
<section id="jms-channel">
|
|
<title>JMS Backed Message Channels</title>
|
|
<para>
|
|
The Channel Adapters and Gateways featured above are all intended for applications that are integrating
|
|
with other external systems. The inbound options assume that some other system is sending JMS Messages
|
|
to the JMS Destination and the outbound options assume that some other system is receiving from the
|
|
Destination. The other system may or may not be a Spring Integration application. Of course, when sending
|
|
the Spring Integration Message instance as the body of the JMS Message itself (with the 'extract-payload'
|
|
value set to false), it is assumed that the other system is based on Spring Integration. However,
|
|
that is by no means a requirement. That flexibility is one of the benefits of using a Message-based
|
|
integration option with the abstraction of "channels" or Destinations in the case of JMS.
|
|
</para>
|
|
<para>
|
|
There are cases where both the producer and consumer for a given JMS Destination are intended to be
|
|
part of the same application, running within the same process. This could be accomplished by using a
|
|
pair of inbound and outbound Channel Adapters. The problem with that approach is that two adapters are
|
|
required even though conceptually the goal is to have a single Message Channel. A better option is
|
|
supported as of Spring Integration version 2.0. Now it is possible to define a single "channel" when
|
|
using the JMS namespace.
|
|
<programlisting language="xml"><![CDATA[ <int-jms:channel id="jmsChannel" queue="exampleQueue"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
The channel in the above example will behave much like a normal <channel/> element from the main
|
|
Spring Integration namespace. It can be referenced by both "input-channel" and "output-channel" attributes
|
|
of any endpoint. The difference is that this channel is backed by a JMS Queue instance named "exampleQueue".
|
|
This means that asynchronous messaging is possible between the producing and consuming endpoints, but
|
|
unlike the simpler asynchronous Message Channels created by adding a <queue/> sub-element within a
|
|
non-JMS <channel/> element, the Messages are not just stored in an in-memory queue. Instead those
|
|
Messages are passed within a JMS Message body, and the full power of the underlying JMS provider is then
|
|
available for that channel. Probably the most common rationale for using this alternative would be to
|
|
take advantage of the persistence made available by the <emphasis>store and forward</emphasis> approach
|
|
of JMS messaging. If configured properly, the JMS-backed Message Channel also supports transactions.
|
|
In other words, a producer would not actually write to a transactional JMS-backed channel if its send
|
|
operation is part of a transaction that rolls back. Likewise, a consumer would not physically remove a
|
|
JMS Message from the channel if the reception of that Message is part of a transaction that rolls back.
|
|
Note that the producer and consumer transactions are separate in such a scenario. This is significantly
|
|
different than the propagation of a transactional context across the simple, synchronous <channel/>
|
|
element that has no <queue/> sub-element.
|
|
</para>
|
|
<para>
|
|
Since the example above is referencing a JMS Queue instance, it will act as a point-to-point channel. If
|
|
on the other hand, publish/subscribe behavior is needed, then a separate element can be used, and a JMS
|
|
Topic can be referenced instead.
|
|
<programlisting language="xml"><![CDATA[ <int-jms:publish-subscribe-channel id="jmsChannel" topic="exampleTopic"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
For either type of JMS-backed channel, the name of the destination may be provided instead of a reference.
|
|
<programlisting language="xml"><![CDATA[ <int-jms:channel id="jmsQueueChannel" queue-name="exampleQueueName"/>
|
|
|
|
<jms:publish-subscribe-channel id="jmsTopicChannel" topic-name="exampleTopicName"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
In the examples above, the Destination names would be resolved by Spring's default
|
|
<classname>DynamicDestinationResolver</classname> implementation, but any implementation of the
|
|
<interfacename>DestinationResolver</interfacename> interface could be provided. Also, the JMS
|
|
<interfacename>ConnectionFactory</interfacename> is a required property of the channel, but by default
|
|
the expected bean name would be "connectionFactory". The example below provides both a custom instance
|
|
for resolution of the JMS Destination names and a different name for the ConnectionFactory.
|
|
<programlisting language="xml"><![CDATA[ <int-jms:channel id="jmsChannel" queue-name="exampleQueueName"
|
|
destination-resolver="customDestinationResolver"
|
|
connection-factory="customConnectionFactory"/>]]></programlisting>
|
|
</para>
|
|
</section>
|
|
<section id="jms-selectors">
|
|
<title>Using JMS Message Selectors</title>
|
|
<para>
|
|
With JMS message selectors you can filter <ulink url="http://docs.oracle.com/javaee/6/api/javax/jms/Message.html">JMS Messages</ulink>
|
|
based on JMS headers as well as JMS properties. For example,
|
|
if you want to listen to messages whose custom JMS header
|
|
property <emphasis>fooHeaderProperty</emphasis> equals
|
|
<emphasis>bar</emphasis>, you can specify the following expression:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[fooHeaderProperty = 'bar']]></programlisting>
|
|
<para>
|
|
Message selector expressions are a subset of the <ulink url="http://en.wikipedia.org/wiki/SQL-92">SQL-92</ulink>
|
|
conditional expression syntax, and are defined as part of the
|
|
<emphasis><ulink url="http://download.oracle.com/otn-pub/jcp/7195-jms-1.1-fr-spec-oth-JSpec/jms-1_1-fr-spec.pdf">Java Message Service</ulink></emphasis>
|
|
specification (Version 1.1 April 12, 2002). Specifically, please see
|
|
chapter "3.8 Message Selection". It contains a detailed explanation of the
|
|
expressions syntax.
|
|
</para>
|
|
<para>
|
|
You can specify the JMS message <emphasis>selector</emphasis> attribute
|
|
using XML Namespace configuration for the following Spring Integration
|
|
JMS components:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>JMS Channel</listitem>
|
|
<listitem>JMS Publish Subscribe Channel</listitem>
|
|
<listitem>JMS Inbound Channel Adapter</listitem>
|
|
<listitem>JMS Inbound Gateway</listitem>
|
|
<listitem>JMS Message-driven Channel Adapter</listitem>
|
|
</itemizedlist>
|
|
<important>
|
|
It is important to remember that you cannot reference message body values
|
|
using JMS Message selectors.
|
|
</important>
|
|
</section>
|
|
<section id="jms-samples">
|
|
<title>JMS Samples</title>
|
|
<para>
|
|
To experiment with these JMS adapters, check out the JMS samples available
|
|
in the <emphasis>Spring Integration Samples</emphasis> Git repository:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<ulink url="https://github.com/SpringSource/spring-integration-samples/tree/master/basic/jms">https://github.com/SpringSource/spring-integration-samples/tree/master/basic/jms</ulink>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
There are two samples included. One provides <emphasis>Inbound</emphasis>
|
|
and <emphasis>Outbound Channel Adapters</emphasis>, and the other provides
|
|
<emphasis>Inbound</emphasis> and <emphasis>Outbound Gateways</emphasis>.
|
|
They are configured to run with an embedded
|
|
<emphasis><ulink url="http://activemq.apache.org/">ActiveMQ</ulink></emphasis>
|
|
process, but the samples'
|
|
<emphasis><ulink url="https://github.com/SpringSource/spring-integration-samples/blob/master/basic/jms/src/main/resources/META-INF/spring/integration/common.xml">common.xml</ulink></emphasis>
|
|
<emphasis>Spring Application Context</emphasis> file can easily be modified
|
|
to support either a different JMS provider or a standalone <emphasis>ActiveMQ</emphasis>
|
|
process.
|
|
</para>
|
|
<para>
|
|
In other words, you can split the configuration, so that the
|
|
Inbound and Outbound Adapters are running in separate JVMs. If you have
|
|
<emphasis>ActiveMQ</emphasis> installed, simply modify the
|
|
<emphasis>brokerURL</emphasis> property within the <emphasis>common.xml</emphasis>
|
|
file to use <emphasis>tcp://localhost:61616</emphasis> (instead of
|
|
<emphasis>vm://localhost</emphasis>). Both of the samples accept input
|
|
via stdin and then echo back to stdout. Look at the configuration to see
|
|
how these messages are routed over JMS.
|
|
</para>
|
|
</section>
|
|
|
|
</chapter>
|