

Messaging
Enterprise applications often don't exist in isolation but must interact with other applications and services running within and outside a company. Messaging is a common approach to this problem and support is provided by both Spring and EJB 3.0. There are two basic operations in messaging: sending and receiving. And, typically, there are two methods of receiving messages: explicit message retrieval and automatic notification (listening).
MessagingFunctional Comparison
To explore how Spring and EJB 3.0 each implement the sending of Java Message Service (JMS) messages, consider the sequence of steps I've outlined for the purchasing of an airline ticket (see Figure 1).
A Spring implementation of the TsaScreener object is shown below:
<code> public class TsaPassengerScreenerClientSpring implements TsaPassengerScreener { private JmsTemplate jmsTemplate; private Queue queue; public void screenPassenger(final Passenger passenger) { jmsTemplate.send(queue, new MessageCreator() { public Message createMessage(Session session) throws JMSException { return session.createObjectMessage(passenger); } }); } ... } </code>The necessary configuration to support this implementation is shown below:
<code> <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate" /> <bean id="tsaQueue" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiTemplate"> <ref bean="jndiTemplate" /> </property> <property name="jndiName"> <value>java:comp/env/queue/tsaQueue</value> </property> </bean> <bean id="tsaQCF" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiTemplate"> <ref bean="jndiTemplate" /> </property> <property name="jndiName"> <value>java:comp/env/queue/tsaQCF</value> </property> </bean> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <constructor-arg> <ref bean="tsaQCF" /> </constructor-arg> </bean> <bean id="tsaPassengerScreener" class="org.jug.flight.booking.spring.TsaPassengerScreenerClientSpring"> <property name="jmsTemplate" ref="jmsTemplate" /> <property name="tsaQueue" ref="tsaQCF" /> </bean> </code>Compare this to the EJB 3.0 implementation:
<code> @Stateless public class TsaPassengerScreenerClientEJB implements TsaPassengerScreener { @Resource(mappedName = "java:/ConnectionFactory") QueueConnectionFactory factory; @Resource(mappedName = "queue/tsaQueue") Queue queue; public void screenPassenger(Passenger passenger) { try { QueueConnection con = factory.createQueueConnection(); QueueSession session = con.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE); ObjectMessage msg = session.createObjectMessage(passenger); QueueSender sender = session.createSender(queue); sender.send(msg); session.close(); con.close(); } catch (Exception e) { e.printStackTrace(); } } } </code>
![]() | |
Figure 1. Purchase Ticket Sequence Diagram. In this example the purchase ticket use case has been expanded to send a message to the TSA with the details of the passenger who is booking a flight. |
Notice that the Spring implementation uses the JmsTemplate helper class to simplify working with the JMS API to send the message. Also, notice that in both cases the container injects the JMS resources (queue connection factory and queue) into the screener object. I'll explore injection more later, in the section on dependency management. But at this point it is interesting to note the Spring configuration is more verbose then the EJB equivalent.
After the passenger details message has been sent the TSA needs to receive and process it. Both Spring and EJB 3.0 can support notification of objects when incoming messages arrive. These objects are referred to as message listeners. A Spring implementation of a message-driven POJO (MDP) is shown below:
<code> public class TsaPassengerScreenerMDP implements MessageListener { public void onMessage(Message message) { ObjectMessage objectMessage = (ObjectMessage) message; try { Passenger passenger = (Passenger) objectMessage.getObject(); // Process message } catch (JMSException e) { e.printStackTrace(); } } } </code>The necessary configuration to support this implementation is shown below:
<code> <bean id="tsaListener" class="org.jug.flight.booking.spring.TsaPassengerScreenerMDP" /> <bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="concurrentConsumers" value="5" /> <property name="connectionFactory" ref="tsaQCF" /> <property name="destination" ref="tsaQueue" /> <property name="messageListener" ref="tsaListener" /> </bean> </code>Compare this to the EJB 3.0 implementation of a message-driven bean (MDB):
<code> @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/tsaQueue") }) public class TsaPassengerScreenerMDB implements MessageListener { public void onMessage(Message message) { ObjectMessage objectMessage = (ObjectMessage) message; try { Passenger passenger = (Passenger) objectMessage.getObject(); // Process message } catch (JMSException e) { e.printStackTrace(); } } } </code>As shown above, both Spring and EJB 3.0 enable the sending and receiving of JMS messages. And interestingly the implementations of message consumption via a Spring MDP and an EJB MDB are quite similar. Additionally, both solutions allow the volume of concurrent message processing to be throttled allowing you to tune the amount of resources allocated within an application to message processing. In the case of EJBs this is a container-specific function whereas with Spring it is a function of the message listener container.
Another important feature of enterprise messaging solutions is their ability to participate in distributed transactions. Often multiple resources will be involved in message processing (typically messaging and database resources) and the work performed on these resources should be performed atomically. Both Spring and EJB 3.0 allow messaging activities to participate in distributed transactions. In EJB 3.0 however, in order to have message acknowledgement tied to successful completion of a transaction, you will need to use container-managed transactions, otherwise messages that have been previously processed may be redelivered. The same can be accomplished in Spring when using JTA transactions and when the message container is defined as "sessionTransacted." In either case you could choose to allow message redelivery and handle this case programmatically.
A more telling difference in messaging support between Spring and EJB is the type of objects that can be configured to listen for incoming messages. In EJB message listeners must be EJB components whereas in Spring any POJO can potentially be activated in response to incoming messages. Both require that the message listener implement an interface and both support the javax.jms.MessageListener interface for JMS message listeners. However, since the 2.1 version of the EJB specification EJB MDBs can support other messaging interfaces such as javax.resource.cci.MessageListener which allow MDBs to be activated by a JCA CCI connector.
MessagingNon-Functional Comparison
Most Java applications use JMS to interact with an underlying message provider. This is the case with both Spring and EJB 3.0. But Spring provides templates that assist with retrieving the necessary message resources from the application server (via JNDI) and for creating, sending, and receiving messages. EJB 3.0 allows message resources to be injected into a class via its dependency injection facilities, but it does not provide any facility equivalent to Spring's template to simplify the use of the JMS API. Spring also provides message converters which can automate the conversion of Java objects to message content.
In terms of standardization both approaches support the Java standard for messaging, JMS. In terms of implementation however MDBs are a JCP standard whereas Spring MDPs are not. But although MDPs are not a standard they are portable as the Spring runtime can run in any JSE or JEE container.
MessagingSummary
Table 1 summarizes the key differences between Spring and EJB 3.0s messaging support.
Table 1. Messaging Features in Spring and EJB 3.0.
Feature | Spring | EJB 3.0 |
Message Listening | ||
Listener Types | Any POJOimplementing the javax.jms.MessageListener interface | MDBs implementing any interface appropriate to its messaging type, usually javax.jms.MessageListener |
Message Throttling | (Container specific) | |
Messaging Support | (Templates, Message Converters) | -- (No support above the JMS API) |
Distributed Transaction Support |