Spring Study Notes - Copyright © 2010 Gavin Lasnitzki Index   Notes   Objectives
Spring with JNDI and JMS

18. Enterprise Java Beans (EJB) integration

18.1. Introduction

Spring does not prevent you from using EJBs.
Spring makes it much easier to access EJBs and implement EJBs and functionality within them.
Using Spring to access services provided by EJBs allows the implementation of those services to later transparently be switched between local EJB, remote EJB, or POJO (plain old Java object) variants, without the client code having to be changed.

18.2. Accessing EJBs

18.2.1. Concepts Question

To invoke a method on a local or remote stateless session bean without Spring:

  • Perform a JNDI lookup to obtain the (local or remote) EJB Home object.
  • Use a 'create' method call on that object to obtain the actual (local or remote) EJB object.
  • One or more methods are then invoked on the EJB.

To avoid repeated low-level code, many EJB applications use the Service Locator and Business Delegate patterns.
As a result:

  • Code the depends on the Service Locator or Business Delegate is hard to test.
  • Code is tied to the EJB API (as it has to invoke the create method and handle the resulting exceptions).
  • Implementing the Business Delegate pattern typically results in significant code duplication.

The Spring approach is to allow the creation and use of proxy objects, normally configured inside a Spring container, which act as codeless business delegates.

18.2.2. Accessing local SLSBs

The following creates the EJB proxy.
The EJB local home is cached on startup, so there’s only a single JNDI lookup.

 

or

18.2.3. Accessing remote SLSBs

18.2.4. Accessing EJB 2.x SLSBs versus EJB 3 SLSBs

18.3. Using Spring's EJB implementation support classes

18.3.1. EJB 2.x base classes

18.3.2. EJB 3 injection interceptor

19. JMS (Java Message Service)

19.1. Introduction Question

Spring simplifies the use of the JMS API and shields the user from differences between the JMS 1.0.2 and 1.1 APIs.

JMS is about the production and consumption of messages.
The JmsTemplate class is used for message production and synchronous message reception.
Asynchronous reception (similar to J2EE's message-driven bean style), is provided by message listener containers that are used to create Message-Driven POJOs (MDPs).

JMS Specification
JMS 1.0.2 defined two types of messaging domains, point-to-point (Queues) and publish/subscribe (Topics), but provided parallel class hierarchies.
JMS 1.1 introduced the concept of domain unification that minimized both the functional differences and client API differences between the two domains.

Spring packages: Question

  • ...jms.core - simplifies JMS by handling the creation and release of resources.
  • ...jms.support - provides JMSException translation functionality (converts the checked JMSException hierarchy to a mirrored hierarchy of unchecked exceptions).
  • ...jms.support.converter - provides a MessageConverter abstraction to convert between Java objects and JMS messages.
  • ...jms.support.destination - provides various strategies for managing JMS destinations, such as providing a service locator for destinations stored in JNDI.
  • ...jms.connection - provides an implementation of the ConnectionFactory suitable for use in standalone applications and a PlatformTransactionManager that allows seamless integration of JMS as a transactional resource into Spring's transaction management mechanisms.

19.2. Using Spring JMS

Objectives: 5.1 Configuring JMS Resources with Spring

19.2.1. JmsTemplate

The JmsTemplate uses the JMS 1.1 API and the subclass JmsTemplate102 uses the JMS 1.0.2 API.

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 (uses default values).
In the JmsTemplate, QOS parameters have been exposed as bean properties to avoid duplication of methods.

Instances of the JmsTemplate class are thread-safe once configured. Question

JmsTemplate supports the sending of messages to both Queues and Topics. Question

19.2.2. Connections Key

The JmsTemplate requires a reference to a ConnectionFactory

19.2.3. Destination Management Key

Destinations, like ConnectionFactories, are JMS administered objects that can be stored and retrieved in JNDI.

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.

19.2.4. Message Listener Containers

Spring alternative to message-driven beans (MDBs) is message-driven POJOs (MDPs).
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 JMS (Java Message Service) 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 and exception conversion.

19.2.4.1. SimpleMessageListenerContainer

Creates a fixed number of JMS sessions at startup.

19.2.4.2. DefaultMessageListenerContainer

Allow for dynamic adaption to runtime demands.
It is able to participate in externally managed transactions (XA transaction).

19.2.4.3. ServerSessionMessageListenerContainer

Leverages the JMS ServerSessionPool SPI to allow for dynamic management of JMS session.
Provides dynamic runtime tuning.

19.2.5. Transaction management

JmsTransactionManager that manages transactions for a single JMS ConnectionFactory.
The JmsTransactionManager performs local resource transactions, binding a JMS Connection/Session pair from the specified ConnectionFactory to the thread.

JmsTemplate can also be used with the JtaTransactionManager and an XA-capable JMS ConnectionFactory for performing distributed transactions.
In a J2EE environment, the ConnectionFactory will pool Connections and Sessions, so those resources are efficiently reused across transactions.

19.3. Sending a Message

Objectives: 5.2 Sending Messages

 

Spring's JmsGatewaySupport convenience base class, which provides pre-built bean properties for JMS configuration.

19.3.1. Using Message Converters Key

The overloaded methods convertAndSend and receiveAndConvert in JmsTemplate delegate the conversion process to an instance of the MessageConverter interface. Question

To accommodate the setting of a message's properties, headers, and body that can not be generically encapsulated inside a converter class, the MessagePostProcessor interface gives you access to the message after it has been converted, but before it is sent.

19.3.2. SessionCallback and ProducerCallback Key

The SessionCallback and ProducerCallback expose the JMS Session and Session / MessageProducer pair respectfully.

19.4. Receiving a message

Objectives: 5.3 Receiving Messages

19.4.1. Synchronous Reception Key

JmsTemplate receive() methods are blocking / synchronous in nature. Question
This can be a dangerous operation since the calling thread can potentially be blocked indefinitely.
The property receiveTimeout specifies how long the receiver should wait before giving up waiting for a message.

19.4.2. Asynchronous Reception - Message-Driven POJOs Key

An MDP must implement the javax.jms.MessageListener interface.
POJO that will be receiving messages must be thread-safe.

 

Define and configure one of the message listener containers

19.4.3. The SessionAwareMessageListener interface

The SessionAwareMessageListener interface is a Spring-specific interface that provides a similar contract the JMS MessageListener interface.
It can be implemented as an alternative to the MessageListener interface.
It provides the message handling method with access to the JMS Session from which the Message was received.

19.4.4. The MessageListenerAdapter

It allows you to expose almost any class as a MDP.
For JMS 1.0.2 API, use the MessageListenerAdapter102.

 

The name of the message handling method in a MessageListenerAdapter defaults to 'handleMessage', but can be changed using the "defaultListenerMethod" property.

MessageListenerAdapter can automatically send back a response Message if a handler method returns a non-void value.
The resulting message will then be sent to the Destination (if one exists) defined in the JMS Reply-To property of the original message, or the default Destination set on the MessageListenerAdapter.

19.4.5. Processing messages within transactions

Invoking a message listener within a transaction only requires reconfiguration of the listener container.

Local resource transactions can simply be activated through the sessionTransacted flag on the listener container definition.
Sending a response message (via SessionAwareMessageListener) will be part of the same local transaction, but any other resource operations (such as database access) will operate independently.

 

Use DefaultMessageListenerContainer to participate in externally managed transactions.

Use JtaTransactionManager to participate in XA transactions.

19.5. Support for JCA Message Endpoints

19.6. JMS Namespace Support

 

Attributes of the JMS <listener> element

Attribute Description
id

A bean name for the hosting listener container. If not specified, a bean name will be automatically generated.

destination (required)

The destination name for this listener, resolved through the DestinationResolver strategy.

ref (required)

The bean name of the handler object.

method

The name of the handler method to invoke. If the ref points to a MessageListener or Spring SessionAwareMessageListener, this attribute may be omitted.

response-destination

The name of the default response destination to send response messages to. This will be applied in case of a request message that does not carry a "JMSReplyTo" field. The type of this destination will be determined by the listener-container's "destination-type" attribute. Note: This only applies to a listener method with a return value, for which each result object will be converted into a response message.

subscription

The name of the durable subscription, if any.

selector

An optional message selector for this listener.

 

Attributes of the JMS <listener-container> element

Attribute Description
container-type

The type of this listener container. Available options are: default, simple, default102, or simple102 (the default value is 'default').

connection-factory

A reference to the JMS ConnectionFactory bean (the default bean name is 'connectionFactory').

task-executor

A reference to the Spring TaskExecutor for the JMS listener invokers.

destination-resolver

A reference to the DestinationResolver strategy for resolving JMS Destinations.

message-converter

A reference to the MessageConverter strategy for converting JMS Messages to listener method arguments. Default is a SimpleMessageConverter.

destination-type

The JMS destination type for this listener: queue, topic or durableTopic. The default is queue.

client-id

The JMS client id for this listener container. Needs to be specified when using durable subscriptions.

cache

The cache level for JMS resources: none, connection, session, consumer or auto. By default (auto), the cache level will effectively be "consumer", unless an external transaction manager has been specified - in which case the effective default will be none (assuming J2EE-style transaction management where the given ConnectionFactory is an XA-aware pool).

acknowledge

The native JMS acknowledge mode: auto, client, dups-ok or transacted. A value of transacted activates a locally transacted Session. As an alternative, specify the transaction-manager attribute described below. Default is auto.

transaction-manager

A reference to an external PlatformTransactionManager (typically an XA-based transaction coordinator, e.g. Spring's JtaTransactionManager). If not specified, native acknowledging will be used (see "acknowledge" attribute).

concurrency

The number of concurrent sessions/consumers to start for each listener. Can either be a simple number indicating the maximum number (e.g. "5") or a range indicating the lower as well as the upper limit (e.g. "3-5"). Note that a specified minimum is just a hint and might be ignored at runtime. Default is 1; keep concurrency limited to 1 in case of a topic listener or if queue ordering is important; consider raising it for general queues.

prefetch

The maximum number of messages to load into a single session. Note that raising this number might lead to starvation of concurrent consumers!