The JmsTemplate
class is the central class
in the JMS core package. It simplifies the use of JMS since it handles
the creation and release of resources when sending or synchronously
recieving messages.
Code that uses the JmsTemplate
only needs
to implement callback interfaces giving them a clearly defined high
level contract. The MessageCreator
callback
interface creates a message given a
Session
provided by the calling code in
JmsTemplate
. In order to allow for more complex
usage of the JMS API, the callback
SessionCallback
provides the user with the JMS
session and the callback ProducerCallback
exposes
a Session
and
MessageProducer
pair.
The JMS API exposes two types of send methods, one that takes
delivery mode, priority, and time-to-live as Quality of Service (QOS)
parameters and one that takes no QOS parameters which uses default
values. Since there are many send methods in
JmsTemplate
, the setting of the QOS parameters
have been exposed as bean properties to avoid duplication in the number
of send methods. Similarly, the timeout value for synchronous receive
calls is set using the property
setReceiveTimeout
.
Some JMS providers allow the setting of default QOS values
administratively through the configuration of the ConnectionFactory.
This has the effect that a call to
MessageProducer
's send method
send(Destination destination, Message message)
will use different QOS default values than those specified in the JMS
specification. In order to provide consistent management of QOS values,
the JmsTemplate
must therefore be specifically
enabled to use its own QOS values by setting the boolean property
isExplicitQosEnabled to
true
.
Note | |
---|---|
Instances of the |
The JmsTemplate
requires a reference to a
ConnectionFactory
. The
ConnectionFactory
is part of the JMS
specification and serves as the entry point for working with JMS. It is
used by the client application as a factory to create connections with
the JMS provider and encapsulates various configuration parameters, many
of which are vendor specific such as SSL configuration options.
When using JMS inside an EJB, the vendor provides implementations
of the JMS interfaces so that they can participate in declarative
transaction management and perform pooling of connections and session.
In order to use this implementation, Java EE containers typically require
that you declare a JMS connection factory as a
resource-ref inside the EJB or servlet deployment
descriptors. To ensure the use of these features with the
JmsTemplate
inside an EJB, the client application
should ensure that it references the managed implementation of the
ConnectionFactory
.
The standard API involves creating many intermediate objects. To send a message the following 'API' walk is performed
ConnectionFactory->Connection->Session->MessageProducer->send
Between the ConnectionFactory and the Send operation there are three intermediate objects that are created and destroyed. To optimise the resource usage and increase performance two implementations of IConnectionFactory are provided.
Spring provides an implementation of the
ConnectionFactory
interface,
SingleConnectionFactory
, that will return the
same Connection
on all
createConnection
calls and ignore calls to
close.
This is useful for testing and
standalone environments so that the same connection can be used for
multiple JmsTemplate
calls that may span any
number of transactions. SingleConnectionFactory
takes a reference to a standard
ConnectionFactory
that would typically come
from JNDI.
The CachingConnectionFactory
extends the
functionality of SingleConnectionFactory
and
adds the caching of Sessions, MessageProducers, and MessageConsumers.
The initial cache size is set to 1, use the property
SessionCacheSize to increase the number of cached
sessions. Note that the number of actual cached sessions will be more
than that number as sessions are cached based on their acknowledgment
mode, so there can be up to 4 cached session instances when
SessionCacheSize is set to one, one for each
AcknowledgementMode. MessageProducers and MessageConsumers are cached
within their owning session and also take into account the unique
properties of the producers and consumers when caching.
MessageProducers are cached based on their destination.
MessageConsumers are cached based on a key composed of the
destination, selector, noLocal delivery flag, and the durable
subscription name (if creating durable consumers).
Destinations, like ConnectionFactories, are JMS administered
objects that can be stored and retrieved in JNDI. When configuring a
Spring application context you can use the JNDI factory class
JndiObjectFactoryBean
/
<jee:jndi-lookup>
to perform dependency
injection on your object's references to JMS destinations. However,
often this strategy is cumbersome if there are a large number of
destinations in the application or if there are advanced destination
management features unique to the JMS provider. Examples of such
advanced destination management would be the creation of dynamic
destinations or support for a hierarchical namespace of destinations.
The JmsTemplate
delegates the resolution of a
destination name to a JMS destination object to an implementation of the
interface DestinationResolver
.
DynamicDestinationResolver
is the default
implementation used by JmsTemplate
and
accommodates resolving dynamic destinations. A
JndiDestinationResolver
is also provided that
acts as a service locator for destinations contained in JNDI and
optionally falls back to the behavior contained in
DynamicDestinationResolver
.
Quite often the destinations used in a JMS application are only
known at runtime and therefore cannot be administratively created when
the application is deployed. This is often because there is shared
application logic between interacting system components that create
destinations at runtime according to a well-known naming convention.
Even though the creation of dynamic destinations are not part of the JMS
specification, most vendors have provided this functionality. Dynamic
destinations are created with a name defined by the user which
differentiates them from temporary destinations and are often not
registered in JNDI. The API used to create dynamic destinations varies
from provider to provider since the properties associated with the
destination are vendor specific. However, a simple implementation choice
that is sometimes made by vendors is to disregard the warnings in the
JMS specification and to use the TopicSession
method createTopic(String topicName)
or the
QueueSession
method
createQueue(String queueName)
to create a new
destination with default destination properties. Depending on the vendor
implementation, DynamicDestinationResolver
may
then also create a physical destination instead of only resolving
one.
The boolean property pubSubDomain is used to
configure the JmsTemplate
with knowledge of what
JMS domain is being used. By default the value of this property is
false, indicating that the point-to-point domain, Queues, will be used.
This property is used by JmsTemplate
determines
the behavior of dynamic destination resolution via implementations of
the DestinationResolver
interface.
You can also configure the JmsTemplate
with
a default destination via the property
defaultDestination. The default destination will be
used with send and receive operations that do not refer to a specific
destination.
One of the most common uses of JMS messages in the EJB world is to drive message-driven beans (MDBs). Spring offers a solution to create message-driven POJOs (MDPs) in a way that does not tie a user to an EJB container. (See Section 21.4.2, “Asynchronous Reception - Message-Driven POJOs” for detailed coverage of Spring's MDP support.)
A message listener container is used to receive messages from a JMS message queue and drive the MessageListener that is injected into it. The listener container is responsible for all threading of message reception and dispatches into the listener for processing. A message listener container is the intermediary between an MDP and a messaging provider, and takes care of registering to receive messages, participating in transactions, resource acquisition and release, exception conversion and suchlike. This allows you as an application developer to write the (possibly complex) business logic associated with receiving a message (and possibly responding to it), and delegates boilerplate JMS infrastructure concerns to the framework.
There are three standard JMS message listener containers packaged with Spring, each with its specialised feature set.
This message listener container is the simplest of the three standard flavors. It simply creates a fixed number of JMS sessions at startup and uses them throughout the lifespan of the container. This container doesn't allow for dynamic adaption to runtime demands or participate in externally managed transactions. However, it does have the fewest requirements on the JMS provider: This listener container only requires simple JMS API compliance.
This message listener container is the one used in most cases.
In contrast to SimpleMessageListenerContainer
,
this container variant does allow for dynamic adaption to runtime
demands and is able to participate in externally managed transactions.
Each received message is registered with an XA transaction (when
configured with a JtaTransactionManager
);
processing can take advantage of XA transation semantics. This
listener container strikes a good balance between low requirements on
the JMS provider and good functionality including transaction
participation.
This listener container leverages the JMS ServerSessionPool SPI
to allow for dynamic management of JMS sessions. The use of this
variety of message listener container enables the provider to perform
dynamic runtime tuning but, at the expense of requiring the JMS
provider to support the ServerSessionPool SPI. If there is no need for
provider-driven runtime tuning, look at the
DefaultMessageListenerContainer
or the
SimpleMessageListenerContainer
instead.
Spring provides a JmsTransactionManager
that manages transactions for a single JMS
ConnectionFactory
. This allows JMS applications
to leverage the managed transaction features of Spring as described in
Chapter 10, Transaction Management. The
JmsTransactionManager
performs local resource
transactions, binding a JMS Connection/Session pair from the specified
ConnectionFactory
to the thread.
JmsTemplate
automatically detects such
transactional resources and operates on them accordingly.
In a Java EE environment, the
ConnectionFactory
will pool Connections and
Sessions, so those resources are efficiently reused across transactions.
In a standalone environment, using Spring's
SingleConnectionFactory
will result in a shared
JMS Connection
, with each transaction having its
own independent Session
. Alternatively, consider
the use of a provider-specific pooling adapter such as ActiveMQ's
PooledConnectionFactory
class.
JmsTemplate
can also be used with the
JtaTransactionManager
and an XA-capable JMS
ConnectionFactory
for performing distributed
transactions. Note that this requires the use of a JTA transaction
manager as well as a properly XA-configured ConnectionFactory! (Check
your Java EE server's / JMS provider's documentation.)
Reusing code across a managed and unmanaged transactional
environment can be confusing when using the JMS API to create a
Session
from a Connection
.
This is because the JMS API has only one factory method to create a
Session
and it requires values for the
transaction and acknowledgement modes. In a managed environment, setting
these values is the responsibility of the environment's transactional
infrastructure, so these values are ignored by the vendor's wrapper to
the JMS Connection. When using the JmsTemplate
in
an unmanaged environment you can specify these values through the use of
the properties sessionTransacted
and
sessionAcknowledgeMode
. When using a
PlatformTransactionManager
with
JmsTemplate
, the template will always be given a
transactional JMS Session
.