Wednesday, December 19, 2012

Integrating Spring with JMS


Introduction

Java Messaging Service opened the door for modeling the asynchronous mode of communication. It provides a common way ofsending and receiving messages by having a middle man, also called as Message Broker orMessage oriented Middleware. Now with the capability of an asynchronous framework like JMSbeing integrated with Spring, it can take all the benefits of Spring and this article shows you the steps of integrating Spring with the JMS framework. This article assumes that you have a fair bit of knowledge in Spring as well as in JMS.

The Spring’s way

Let’s us see how we can integrate the Spring for programming the asynchronous model using JMS. For that to happen, we need to use a Message Broker that acts as a middle man sitting between the sender and the receiving application. The example we are going to use makes use of the popular open sourceMessage Broker, the ActiveMQ. Before continuing with the sample application, the necessary softwares, the Spring framework and the ActiveMQ Message Broker can be downloaded from ‘http://www.springsource.com/download/community?project=Spring%20Framework’ and ‘https://activemq.apache.org/’.

Configuring the Connection Factory

In this section, we shall see how we can define a connection factory instance that provides the entry point for interacting with the JMS. It can be used to interact with the ActiveMQ Message Broker for creating a connection, through which a session can be established for sending and receiving messages. Examine the following definition,
1
2
3
4
<bean id="activeMQConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://jmsserver:9999"/>
</bean>
Note that when defining the bean it is mandatory that the class name that corresponds to the name of the Connection Factory of the Message Broker has to be known by looking into the vendor’s documentation, in our case, this happens to be'org.apache.activemq.ActiveMQConnectionFactory'. We have also specified the URL where the server is running by making use of the property 'brokerURL'.

Configuring the Message Destination

A message destination refers to an abstract location where a message can be posted by a sender that will be received, later on, by the receiver. JMS supports two forms of messaging mode. They are
  • Point to Point Messaging
  • Publish Subscribe Messaging

Point to Point Messaging

In point to point messaging, the sender will post a message in a message destination called Queue. The sender application will make use of the Message Broker for placing the message in the Queue. Even though there may be multiple receiving applications that will be waiting for the message to get picked up, as soon as a receiver picks up the message, the copy of the message will be destroyed. The following code declares a JMS queue by name 'sampleQueue'.
1
2
3
<bean id="sampleQueue"
class="org.apache.activemq.command.ActiveMQQueue">
</bean>

Publish Subscribe Messaging

As the name suggests, in publish-subscribe messaging, the sending application will post the message in a message destination and there can be more than one receiving applications who will get the message. The message destination in publish subscribe messaging is called Topic. For defining a topic with name 'sampleTopic' using Spring’s bean definition, use the following code,
1
2
3
4
5
</p>
<p align="justify"><bean id="sampleTopic"
class="org.apache.activemq.command.ActiveMQTopic">
</bean></p>
<p align="justify">

Defining the JMS Template class

In a traditional JMS application that acts as a sender, there will be huge amount of boilerplate code right from creating the connection factory instance, creating the session and sending the message as well as enclosing the code in a bunch of try-catch constructs for catching any JMS Exceptions. Spring’sJMSTemplate class simplifies the life of sending the message by eradicating all the boiler plate code asking the developer to concentrate only on the core business logic, i.e sending the message. Here is the declaration of the JMS Template class as a Spring bean,
1
2
3
4
<bean id="sampleJmsTemplate"
class="org.springframework.jms.core.JmsTemplate">
<property name=" connectionFactory" ref=" activeMQConnectionFactory" />
</bean>
Note that the JMS Template object needs to be aware of the connection factory reference through which it will contact the Message Broker for establishing connection and session.

Sending a message

Let us keep the example as simple as sending the traditional ‘Hello World’ message since the main motive of this sample is to show that how Spring can be integrated with JMS. Let us see the declaration of the sample message sending application class which is shown below,
MessageSender.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package net.javabeat.spring.jms;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
public class MessageSender
{
    private Destination destination;
    private JmsTemplate jmsTemplate;
    public MessageSender() {}
    public void setJmsTemplate(JmsTemplate jmsTemplate)
    {
        this.jmsTemplate = jmsTemplate;
    }
    public void setDestination(Destination destination)
    {
        this.destination = destination;
    }
    public void sendMessage()
    {
        MessageCreator creator = new MessageCreator()
        {
            public Message createMessage(Session session)
            {
                TextMessage message = null;
                try
                {
                    message = session.createTextMessage();
                    message.setStringProperty("text", "Hello World");
                }
                catch (JMSException e)
                {
                    e.printStackTrace();
                }
                return message;
        }
    };
    jmsTemplate.send(destination, creator);
    }
}
The MessageSender class needs to be aware of two things, one is the destination object where the message has to be sent and the other being the JMSTemplate object that simplifies the process of sending the message. The sending of the message is defined by the method JMSTemplate.send()that takes 2 arguments. The first argument is the message destination itself and the second argument is the message creator object that knows how to create a message that can be sent later. In our example case, we had constructed a simple ‘Hello World’ message and the following shows how to encapsulate the message sender class as a spring bean.

Receiving the message

Receiving the message from the Message Broker is as simple as sending the message as the following code justifies it.
MessageReceiver.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package net.javabeat.spring.jms;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.TextMessage;
import org.springframework.jms.core.JmsTemplate;
public class MessageReceiver
{
    private JmsTemplate jmsTemplate;
    private Destination destination;
    public MessageReceiver() {}
    public void setJmsTemplate(JmsTemplate jmsTemplate)
    {
        this.jmsTemplate = jmsTemplate;
    }
    public void setDestination(Destination destination)
    {
        this.destination = destination;
    }
    public void receiveMessage()
    {
        Message message = jmsTemplate.receive();
        TextMessage textMessage = null;
        if (message instanceof TextMessage)
        {
            textMessage = (TextMessage)message;
            try
            {
                System.out.println(textMessage.getStringProperty("text"));
            }
            catch (JMSException e)
            {
                e.printStackTrace();
            }
       }
    }
}
And here is the bean definition for the message receiver class,

No comments: