Maven Dependency:
org.apache.activemq activemq-all ${activemq.version} org.apache.activemq activemq-jaas ${activemq.version} org.apache.activemq activemq-spring ${activemq.version} org.springframework spring-beans ${spring.version} org.springframework spring-context ${spring.version} org.springframework spring-jms ${spring.version} org.springframework spring-test ${spring.version} log4j log4j 1.2.17 commons-logging commons-logging 1.2 junit junit 4.8.1
Using Spring to Send JMS Messages
1. applicationContext.xml:
xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.huey.hello" /> <bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://10.1.242.146:61616" /> bean> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="connectionFactory" /> <property name="defaultDestination" ref="helloQueue" /> bean> <bean id="helloQueue" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg index="0" value="example.HelloQueue" /> bean> beans>
2. Test Code:
public class AMQTest extends SpringTest { @Resource(name = "jmsTemplate") JmsTemplate jmsTemplate; @Resource(name = "helloQueue") Destination helloQueue; @Test public void testSendMessage() throws Exception { jmsTemplate.send(helloQueue, new MessageCreator() { public Message createMessage(Session session) throws JMSException { return session.createTextMessage("Hello, ActiveMQ!"); } }); System.out.println("Send the message successfully."); } }
Using Spring to Receive JMS Messages Synchronously
1. applicationContext.xml:
xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.huey.hello" /> <bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://10.1.242.146:61616" /> bean> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="connectionFactory" /> <property name="defaultDestination" ref="helloQueue" /> bean> <bean id="helloQueue" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg index="0" value="example.HelloQueue" /> bean> beans>
2. Test Code:
public class AMQTest extends SpringTest { @Resource(name = "jmsTemplate") JmsTemplate jmsTemplate; @Resource(name = "helloQueue") Destination helloQueue; @Test public void testReceiveSyncMessage() throws Exception { Message message = jmsTemplate.receive(); if (message == null) { System.out.println("There are not any messages."); return; } if (message instanceof TextMessage) { TextMessage textMessage = (TextMessage) message; System.out.println("Receive a text message: " + textMessage.getText()); } else { System.out.println("Receive a non-text message."); } } }
Using Spring to Receive JMS Messages Asynchronously
1. applicationContext.xml:
xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.huey.hello" /> <bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://10.1.242.146:61616" /> bean> <bean id="helloQueue" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg index="0" value="example.HelloQueue" /> bean> <bean id="myQueueMessageListener" class="com.huey.hello.activemq.MyQueueMessageListener" /> <bean id="queueJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory" /> <property name="destination" ref="helloQueue" /> <property name="messageListener" ref="myQueueMessageListener" /> bean> beans>
2. MyQueueMessageListener:
package com.huey.hello.activemq; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; public class MyQueueMessageListener implements MessageListener { public void onMessage(Message message) { try { if (message == null) { System.out.println("There are not any messages."); return; } if (message instanceof TextMessage) { TextMessage textMessage = (TextMessage) message; System.out.println("Receive a text message: " + textMessage.getText()); } else { System.out.println("Receive a non-text message."); } } catch (Exception e) { e.printStackTrace(); } } }
Working with Spring's JmsTemplate
Spring supports a handy abstraction, JmsTemplate, which allows you to hide some of the lower level JMS details when sending messages etc.
One thing to bear in mind with JmsTemplate is that by default it will create a new connection, session, producer for each message sent - then close them all down again. This is very inefficient! It is done like this to work in EJB containers which tend to use a special ConnectionFactory which does pooling.
If you are not using a JCA container to manage your JMS connections, we recommend you use our pooling JMS connection provider, (org.apache.activemq.pool.PooledConnectionFactory) from the activemq-pool
library, which will pool the JMS resources to work efficiently with Spring's JmsTemplate or with EJBs.
e.g.
xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.huey.hello" /> <bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://10.1.242.146:61616" /> bean> <bean id="jmsFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop"> <property name="connectionFactory" ref="connectionFactory" /> bean> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="jmsFactory" /> <property name="defaultDestination" ref="helloQueue" /> bean> beans>
The PooledConnectionFactory
supports the pooling of Connection, Session and MessageProducer instances so it can be used with tools like Camel and Spring's JmsTemplate and MessagListenerContainer . Connections, sessions and producers are returned to a pool after use so that they can be reused later without having to undergo the cost of creating them again.
Note: while the PooledConnectionFactory
does allow the creation of a collection of active consumers, it does not 'pool' consumers. Pooling makes sense for connections, sessions and producers, which can be seldom-used resources, are expensive to create and can remain idle a minimal cost. Consumers, on the other hand, are usually just created at startup and left going, handling incoming messages as they come. When a consumer is complete, it's preferred to shut down it down rather than leave it idle and return it to a pool for later reuse: this is because, even if the consumer is idle, ActiveMQ will keep delivering messages to the consumer's prefetch buffer, where they'll get held up until the consumer is active again.
If you are creating a collection of consumers (for example, for multi-threaded message consumption), you should consider keeping a low prefetch value (e.g. 10 or 20), to ensure that all messages don't end up going to just one of the consumers.
Spring's MessagListenerContainer should be used for message consumption. This provides all the power of MDBs - efficient JMS consumption and pooling of the message listeners - but without requiring a full EJB container.
You can use the activemq-pool
org.apache.activemq.pool.PooledConnectionFactory
for efficient pooling of the connections and sessions for your collection of consumers, or you can use the Spring JMS org.springframework.jms.connection.CachingConnectionFactory
to achieve the same effect.