Monday, June 15, 2009

Spring + JMS

This blog is been written as part of Spring integration with other technologies. In this blog I am going to explain how to integrate JMS(Java Messaging Service) with spring and to use template mechanism of spring for easy integration of JMS. Spring provides a template mechanism to hide the details of a typical JMS implementation so developers can concentrate on the
actual task of processing messages instead of worrying about how to create, access, or clean up JMS resources.As like other posts on integration I am supposing that you know spring and jms as I will just taking an example which will explain a “Hello World” type example of JMS with Spring.


I will be using Apache ActiveMQ as Message Broker. Please
download the latest one from http://activemq.apache.org/activemq-520-release.html.

So let’s see how can we integrate JMS with Spring. You can get the source code from
http://www.mediafire.com/download.php?wmqmfcnqnjm


Step 1. Configuring the Connection Factory

First thing we have to do is to create connection factory instance which will provide entry point to interact with Message Broker. This is connection factory will be used for sending and receiving messages. Here is the bean definition which will get into your spring configuration file.

<!-- JMS Queue Connection Factory-->

<bean id="activeMQConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>

Step2. Configuring the Message Destination

You can use both queue and topic mode for sending and
receving the messages.

For queue:

<bean id="springJmsQueue" class="org.apache.activemq.command.ActiveMQQueue">
</bean>

And for Topic:

<bean id="springJmsTopic" class="org.apache.activemq.command.ActiveMQTopic">
</bean>

Step 3. Defining the JMS Template class

Normally we create the connection factory instance ,then we create the session and the we send the message and hell lot of try catch blocks and code for closing sessions. Spring's JMSTemplate class simplifies the life of sending the message. Here is the declaration of the JMS Template class as a Spring bean,

<!-- JMS Queue Template -->

<bean id="jmsQueueTemplate"
class="org.springframework.jms.core.JmsTemplate">

<property name="connectionFactory">
<ref bean="activeMQConnectionFactory"/>
</property>
<property name="defaultDestination" ref="ideekshaQueue"></property>
</bean>

JMS Template takes reference for the connection factory through which it will connect to Message Broker.I have used default destination queue to sens and receive messages, you can use you own and declare them for jms receiver and jms sender.

Step 4. Sending a message

Here is the code for sending the JMS message using
JMSTemplate.

JmsSender.java

-------------------------------------------------------------

package com.ideeksha.spring.jms;

import org.springframework.jms.core.JmsTemplate;

public class JmsSender {

private JmsTemplate jmsTemplate;
public JmsTemplate getJmsTemplate() {
return jmsTemplate;
}

public void setJmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}

public void sendMesage() {
jmsTemplate.convertAndSend("HelloWorld!!!!");
}
}


jmsTemplate.convertAndSend() takes destination and the message, as I have use defaultDestination in template it will take that destination and if you want to override this you can pass other destination to convertAndSend().
This is the bean definition for JmsSender.

<bean id="jmsSender" class="com.ideeksha.spring.jms.JmsSender">
<property name="jmsTemplate">
<ref bean="jmsQueueTemplate"/>
</property>
</bean>


Step 5. Receiving the message

Here is the code for receiving the JMS message using JMSTemplate.

JmsReceiver.java

-------------------------------------------------

package com.ideeksha.spring.jms;

import javax.jms.Message;
import javax.jms.TextMessage;

import org.springframework.jms.core.JmsTemplate;

public class JmsReceiver {
private JmsTemplate jmsTemplate;

public JmsTemplate getjmsTemplate() {

return jmsTemplate;

}
public void setjmsTemplate(JmsTemplate jmsTemplate) {

this.jmsTemplate = jmsTemplate;

}
public void processMessage() {

Message msg = jmsTemplate.receive();
try {
TextMessage textMessage = (TextMessage)msg;
if (msg != null) {
System.out.println(" Message Received -->"+ textMessage.getText());

}
} catch (Exception e) {

e.printStackTrace();

}

}

}



And here is the bean definition for the message receiver class,

<bean id="jmsReceiver" class="com.ideeksha.spring.jms.JmsReceiver">
<property name="jmsTemplate">
<ref bean="jmsQueueTemplate"/>
</property>
</bean>


Step 6. Running this application

First we can provide this as a service by declaring a service interface.

This is my service interface:

JmsService.java

-------------------------------------------

package com.ideeksha.spring.jms;

public interface JmsService {

public abstract void process();

}

And here is its implementation

JmsServiceImpl.java
------------------------------------------------------------------

package com.ideeksha.spring.jms;


public class JmsServiceImpl implements JmsService {

private JmsSender sender;

private JmsReceiver receiver;

public JmsSender getSender() {
return sender;
}
public void setSender(JmsSender sender) {
this.sender = sender;
}

public JmsReceiver getReceiver() {
return receiver;
}

public void setReceiver(JmsReceiver receiver) {
this.receiver = receiver;
}

public void process() {
sender.sendMesage();
// uncomment below lines for checking in active mq admin GUI
// try {
// Thread.sleep(10000);
// } catch(InterruptedException e) {
// e.printStackTrace();
// }
receiver.processMessage();
}
}

And finally the main class which will execute this:

App.java

----------------------------------------------------------------------

package com.ideeksha.spring.jms;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

public static void main(String[] args) {

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
JmsServiceImpl service =(JmsServiceImpl) ctx.getBean("jmsService");
service.process();

}

}

And the bean definition for all of this is

<bean id="jmsService" class="com.ideeksha.spring.jms.JmsServiceImpl">
<property name="sender">
<ref bean="jmsSender"/>
</property>
<property name="receiver">
<ref bean="jmsReceiver"/>
</property>
</bean>

But this is synchronous JMS code, but we use jms for asynchronous communication.
So for this we have to modify the Service implementaion and remove the receiver
code.

So out new implementation file will be

JmsServiceImpl.java
--------------------------------------------------------------------

package com.ideeksha.spring.jms;

public class JmsServiceImpl implements
JmsService {

private JmsSender sender;

private JmsReceiver receiver;

public JmsSender getSender() {
return sender;
}

public void setSender(JmsSender sender) {
this.sender = sender;
}
public JmsReceiver getReceiver() {
return receiver;
}
public void setReceiver(JmsReceiver receiver) {
this.receiver = receiver;
}
public void process() {
sender.sendMesage();
}

}

And there will be Message Listener which will listen for one particular destincation queue/topic.
So we have Listener class which will be implementing MessageListener imterface.

Listener.java
-----------------------------------------------------------

package com.ideeksha.spring.jms;


import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;


public class Listener implements MessageListener {

public void onMessage(Message msg) {

if (msg instanceof TextMessage) {
try {
System.out.println("Received msg asynchronously: " + ((TextMessage) msg).getText());

} catch (JMSException e) {
e.printStackTrace();
}

} else {

throw new RuntimeException("This message should be of type TextMessage");
}
}
}

And the bean definition for this is
<!-- This is the Message Driven Pojo (MDP) -->

<bean id="messageListener" class="com.ideeksha.spring.jms.Listener" />


We have to put this Listener in jms Container. For that this is the bean definition of jms container

<!-- This is the message listener container -->

<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="activeMQConnectionFactory"/>
<property name="destination" ref="ideekshaQueue" />
<property name="messageListener" ref="messageListener" />
</bean>

Which will have reference for jms queue on which it will be listening and the listener reference.

In the sample code what I have attached is having synchronous functionality, if you want to do asynchronous uncomment the listener and the container definition from the configuration file.

5 comments :

raja said...

ultimate reference

raja said...

ultimate Reference
thanks a lot Anil

Apurv said...

what classes to use for bean to set up queueconnectionfactory using glassfish jms provider.
Any idea please respond to apurv_agnihoti@infosys.com

Anonymous said...

where is the reference for ideekshaQueue? i couldn't find a configuration details for this. can you please specify.

Anil Verma said...

You can define ideekshaQueue similar to springJmsQueue.In the source code ideekshaQueue is define in applicationContext.xml file.