Here is a sample configuration for using MQ with JMS and Spring.
Firstly the MQ library is needed. This can be found in a number of places but if you are using eclipse you can install the Websphere Liberty Profile (8.5.next) from the market place. The required MQ library is available in
<liberty_install_dir>/lib/com.ibm.ws.messaging.jms.wmq_1.0.jar
Maven Dependencies
The MQ jar can be used as a maven dependency using the System scope using the install directory above.
<dependency>
<groupId>com.ibm.ws.messaging.jms</groupId>
<artifactId>wmq</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath><liberty_install_dir>/lib/com.ibm.ws.messaging.jms.wmq_1.0.jar</systemPath>
</dependency>
The JMS interfaces are all that is necessary if installing into an application server / container.
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
Note that this is a provided dependency because the implementation of these interfaces are provided by the container. If the app is standalone and isn't deployed into a container then concrete implementations of the JMS spec needs to be provided. One example is the geronimo library,
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jms_1.1_spec</artifactId>
<version>1.1.1</version>
<scope>compile</scope>
</dependency>
And finally the spring jms jar is also required,
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>3.1.1.RELEASE</version>
<scope>compile</scope>
</dependency>
(Note: you'll need to add a
spring property place holder for the properties or replace the ${...} values in the following examples)
JMS Connection Factory
The JMS connection factory is dependent on the queue / topic implementation that is being used. In this case this is IBM MQ,
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="${ip_address}" />
<property name="port" value="${port_number}" />
<property name="queueManager" value="${queue_manager_name}" />
<property name="transportType" value="1" />
</bean>
<bean id="jmsDestination" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="${queue_name}" />
</bean>
This will configure a Queue based connection. To create a topic based connection is just as simple. Just replace the 'Queue' with 'Topic' in the configuration above. This gives,
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQTopicConnectionFactory">
<property name="hostName" value="${ip_address}" />
<property name="port" value="${port_number}" />
<property name="queueManager" value="${queue_manager_name}" />
<property name="transportType" value="1" />
</bean>
<bean id="jmsDestination" class="com.ibm.mq.jms.MQTopic">
<constructor-arg value="${topic}" />
</bean>
Spring Connection Factory
The spring connection factory wraps the JMS Connection Factory. There are a number of connection factories available. If this is a simple connection with no authentication then just use,
<bean id="springConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="jmsConnectionFactory" />
</bean>
otherwise if credentials are required use,
<bean id="springConnectionFactory"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="jmsConnectionFactory" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
Spring JMS Template
The JMS template does a lot of the boilerplate code required to open and close connections. It is very like JdbcTemplate from that point of view.
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="springConnectionFactory" />
<property name="defaultDestination" ref="jmsDestination" />
</bean>
Message Driven Bean
A message driven bean is triggered when a message is received by the JMS system. Spring maintains this relationship and in its simplest form it is exactly the same as the standard JMS setup,
<!-- Message driven bean -->
<bean id="sampleMessageDrivenBean" class="com.me.SampleMessageDrivenBean">
</bean>
<!-- and this is the message listener container -->
<bean id="springJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="springConnectionFactory" />
<property name="destination" ref="jmsDestination" />
<property name="messageListener" ref="sampleMessageDrivenBean" />
</bean>
In this case the message driven bean just implements the standard MessageListener interface from JMS,
public class SampleMessageDrivenBean implements MessageListener
{
@Override
public void onMessage(Message message)
{
System.out.println("Message Driven Bean: New Message");
System.out.println(message.toString());
}
}
Spring also provides a session message listener which provides the session object in the onMessage() call.
Sending Messages
Creating a class to send a message is very easy too. Using spring to inject the JmsTemplate and Destination leaves a class to send messages as,
public class MessageSender
{
/**
* JMSTemplate.
*/
private JmsTemplate jmsTemplate;
/**
* JMSTemplate.
*/
private Destination jmsDestination;
/**
* Send a message.
*/
public void sendMessage()
{
jmsTemplate.send(jmsDestination, new MessageCreator()
{
@Override
public Message createMessage(Session session) throws JMSException
{
System.out.println("Message Sent");
final Calendar now = Calendar.getInstance();
return session.createTextMessage(now.toString());
}
});
}
/**
* Sets jmsTemplate to the given value.
*
* @param jmsTemplate the jmsTemplate to set
*/
public void setJmsTemplate(JmsTemplate jmsTemplate)
{
this.jmsTemplate = jmsTemplate;
}
/**
* Sets jmsDestination to the given value.
*
* @param jmsDestination the jmsDestination to set
*/
public void setJmsDestination(Destination jmsDestination)
{
this.jmsDestination = jmsDestination;
}
}