Introduction to messaging with Spring JMS

1 Introduction to Spring JMS

In this post I will show you how to configure a standalone application in order to see different ways of sending and receiving messages using Spring JMS. Basically, I will divide the examples into the following sections:

  • Point-to-point messaging (queue)
    • Synchronous reception
    • Asynchronous reception
  • Publish-subscribe messaging (topic)

The source code with all the examples shown in this article is available at my Github repository.

2 Configuring the provider

The first thing we need to do is to configure the ConnectionFactory. The connection factory is part of the JMS specification and allows the application to create connections with the JMS provider:

<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
    <property name="brokerURL" value="vm://embedded?broker.persistent=false"/>

The factory is used to create a connection which is then used to create a session. In the following examples, we won’t need to care about this since the JmsTemplate class will do this for us.

Spring provides its own ConnectionFactory implementations, which are specified below:

  • SingleConnectionFactory: All createConnection() calls will return the same connection. This is useful for testing.
  • CachingConnectionFactory: It provides caching of sessions.

The JmsTemplate aggressively opens and closes resources like sessions since it assumes that are cached by the connectionFactory. Using the CachingConnectionFactory will improve its performance. In our example, we will define a cachingConnectionFactory passing our previously defined AMQ connectionFactory to its targetConnectionFactory property:

<bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
    <property name="targetConnectionFactory" ref="connectionFactory"/>


3 Point-to-point messaging (queue)

This Destination implementation consists in sending a message to a single consumer. The producer will send a message to the queue where it will be retrieved by the consumer.

point-to-point diagram


The consumer will actively retrieve the message from the queue (synchronous reception) or it will retrieve the message passively (asynchronous reception). Now we will see an example of each.

3.1 Synchronous reception

3.1.1 Configuration

Spring JMS uses JmsTemplate class for message production and synchronous message reception. This template is a central class of Spring JMS, and helps us by:

  • Reducing boilerplate code: It handles the creation and release of resources transparently (connection, session…).
  • Handling exceptions and converting them to runtime exceptions.
  • Providing utility methods and callbacks.

Let’s configure the jmsTemplate:

<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="cachingConnectionFactory"/>
    <property name="defaultDestination" ref="syncTestQueue"/>

This template will handle our point-to-point messaging. To use topics it will need further configuration, which will be shown in the following sections.

The Queue destination is defined below:

<bean id="syncTestQueue" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg value="test.sync.queue"/>

In our example, a producer will send a message to this queue and a consumer will retrieve it.

3.1.2 The producer

public class Producer {
    private JmsTemplate jmsTemplate;
    public void convertAndSendMessage(Notification notification) {


This producer will use a jmsTemplate to send a message. Note the @Component annotation, this class will be auto detected and registered as a bean.

It is also important to see that we are passing a Notification object to the jmsTemplate method. If we do not define a message converter, the template will register a SimpleMessageConverter by default (check JmsTemplate constructor). This converter will be able to convert the following types:

  • String to TextMessage
  • Serializable to ObjectMessage
  • Map to MapMessage
  • byte[] to BytesMessage

If the object being sent is not an instance of any of the previous list, it will throw a MessageConversionException. The common cause of this exception is that your object is not implementing Serializable interface.

In this case, it will convert our Notification object to an ObjectMessage and send it to its default destination, which we previously defined as “test.sync.queue“.

3.1.3 The consumer

public class SyncReceiver {
    private JmsTemplate jmsTemplate;
    public Notification receive() {
        return (Notification) jmsTemplate.receiveAndConvert("test.sync.queue");

You should use this method carefully as it blocks the current thread until it receives the message. You should better define a timeout in case there’s a problem receiving the message. The jmsTemplate has no timeout setter method defined. You will need to define it when configuring the AMQ connection factory:

<property name=”sendTimeout” value=”5000″/>

3.1.4 The test

@ContextConfiguration(locations = {
public class TestSyncMessaging {
    private Producer producer;
    private SyncReceiver syncReceiver;
    public void testSynchronizedReceiving() throws InterruptedException {
        Notification notification = new Notification("1", "this is a message");
        //Sends the message to the jmsTemplate's default destination
        Notification receivedNotification = syncReceiver.receive();
        assertEquals("this is a message", receivedNotification.getMessage());


3.2 Asynchronous reception

Spring lets you receive messages asynchronously in two different ways:

  • Implementing MessageListener interface
  • Using a simple POJO

The following example will show the second approach.

3.2.1 Configuration

We can use the same jmsTemplate we configured in the previous example. In this case we will configure another queue where the producer will send its message and a consumer that will act as a listener:

<bean id="asyncTestQueue" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg value="test.async.queue"/>

<jms:listener-container connection-factory="connectionFactory">
    <jms:listener destination="test.async.queue" ref="asyncReceiver" method="receiveMessage"/>


We are configuring a consumer which will be the asyncReceiver bean, and the listener container will invoke its receiveMessage method when a message arrives to the test.async.queue.

3.2.2 The producer

The producer will be the same defined in the previous section, but it will send the message to a different queue:

public void convertAndSendMessage(String destination, Notification notification) {
    jmsTemplate.convertAndSend(destination, notification);

3.2.3 The consumer

public class AsyncReceiver {
    private NotificationRegistry registry;
    public void receiveMessage(Notification notification) {


As you can see, it’s a simple Java class. It does not need to implement any interface. The consumer saves received notifications to a registry. This registry will be used by the test class to assert that notifications arrived correctly.

3.2.4 The test

@ContextConfiguration(locations = {
public class TestAsyncMessaging {
    private Producer producer;
    private NotificationRegistry registry;
    public void testAsynchronizedReceiving() throws InterruptedException {
        Notification notification = new Notification("2", "this is another message");
        producer.convertAndSendMessage("test.async.queue", notification);
        assertEquals(1, registry.getReceivedNotifications().size());
        assertEquals("this is another message", registry.getReceivedNotifications().get(0).getMessage());


4 Publish-subscribe messaging (topic)

The message is sent to a topic, where it will be distributed to all consumers that are subscribed to this topic.

publish-subscribe diagram


4.1 Configuration

We will need another jmsTemplate since the template we configured before is set to work with queues.

<bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="cachingConnectionFactory"/>
    <property name="pubSubDomain" value="true"/>

We just need to configure its destination accessor by defining its pubSubDomain property and set its value to true. The default value is false (point-to-point).

Next, we configure a new destination, which will be the topic for this example:

<bean id="testTopic" class="org.apache.activemq.command.ActiveMQTopic">
    <constructor-arg value="test.topic"/>

Finally, we define the listeners. We define two listeners to make sure both consumers receive the message sent to the topic by the producer.

<jms:listener-container connection-factory="connectionFactory" destination-type="topic">
    <jms:listener destination="test.topic" ref="asyncTopicFooReceiver" method="receive"/>
    <jms:listener destination="test.topic" ref="asyncTopicBarReceiver" method="receive"/>

You may notice a difference in the listener configuration. We need to change the destination type of the listener container, which is set to queue by default. Just set its value to topic and we are done.

4.2 The producer

public class Producer {
    private JmsTemplate jmsTopicTemplate;
    public void convertAndSendTopic(Notification notification) {
        jmsTopicTemplate.convertAndSend("test.topic", notification);

4.3 The consumer

public class AsyncTopicBarReceiver {
    private NotificationRegistry registry;
    public void receive(Notification notification) {

The asyncTopicFooReceiver has the same method.

4.4 The test

@ContextConfiguration(locations = {
public class TestTopicMessaging {
    private Producer producer;
    private NotificationRegistry registry;
    public void testTopicSending() throws InterruptedException {
        Notification notification = new Notification("3", "this is a topic");
        assertEquals(2, registry.getReceivedNotifications().size());
        assertEquals("this is a topic", registry.getReceivedNotifications().get(0).getMessage());
        assertEquals("this is a topic", registry.getReceivedNotifications().get(1).getMessage());


25 thoughts on “Introduction to messaging with Spring JMS

  1. You can create a dynamic subscriber programmatically from the session, which is created from your injected connection factory:

    Connection con = connectionFactory.createConnection();
    Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
    MessageConsumer consumer = session.createConsumer(destination);

    Then you just need to define a listener for the consumer you've just created.

    I've added a test case named TestDynamicTopicReceiver to my source code. You can check it here:

  2. Hi i am Nagarjuna, superb work, no words to say simply superb explined perfectly.
    I have a doubt how you configured destination and where you created.
    Thank you

  3. Hi Nagarjuna,

    Thanks for your feedback, I appreciate it. I will try to answer your question:

    In synchronous reception you can see the destination defined as a queue named "test.sync.queue" (3.1.1 section). That's the bean named syncTestQueue. This bean is configured in the jmsTemplate as its default destination, so when you use the template to send a message, you can skip the destination and it will use the default (see the producer in 3.1.2 section). On the other hand, the consumer (section 3.1.3) receives the message from the queue passed to the jmsTemplate. The template will use its destination resolver to resolve the name passed to a JMS destination.

    In asynchronous reception, the mechanism is the same.

    Did I answer your question?

  4. Thanks Xavier for this great blog!
    Just another question about this dynamic subscriber code,
    Where this destination @Autowired from? I don't see this anywhere, how does TestDynamicTopicReceiver know it is "test.topic"?

    private Topic destination;

  5. Hi Ziyang,

    Thanks to you for reading it 🙂

    What I am doing in TestDynamicReceiver is autowiring by type. This means it will look at the Spring container for a bean of type javax.jms.Topic. If you review the config file "jms-config.xml", you will notice that there's only one qualifying bean, which is testTopic (ActiveMQTopic implements javax.jms.Topic). The other two destinations implement javax.jms.Queue.

  6. Thanks for the explanation, as I expected, :), in fact, I never used by type in real world.

    I like your blogs very much! Hope you keep on.

    Happy New Year!

  7. Hi Xavier,
    Thank you very much for this helpful and useful post!
    We're trying to configure our application to use JMS topics, but it seems that some of the messages get lost and don't get consumed (it doesn't happen when we use queues).
    For detailed information see my post:
    Do you maybe have an idea what could be the problem? Any help would be very much appreciated. 🙂

  8. Hi Ayelet,

    I've added a test called "TestIterateToTopic" to my project, but doesn't seem to reproduce your issue since all messages are being received by the consumer. I'm using a local JMS transaction. Maybe, as you noted in SO, could be something with Atomikos configuration. I'm sorry for not being more helpful.

    Please, let me know if you find what's wrong.

  9. Hi Xavier,
    We couldn't figure out what the problem was, but when we used virtual topic instead of regular topic, it seemed to solve the issue.

  10. Manuel, thank you for the invitation but, as weird as it may seem, I don't currently have Facebook! I will think about it. Regarding the twitter account, my twitter handle is @xavips. Best regards.

  11. Hi Xavier – I am just learning Spring and JMS and was attempting to learn from your example but could not get the Notification object to work. In your post you send only 2 parameters when creating the Notification object but when I look for that class it comes up in and has more arguments. Can you please explain this line:

    Notification notification = new Notification("1", "this is a message");

    Thank you

  12. Hi Xavi, great blog!!

    I am developing a JMS Subscriber for a data intensive application (Big Data!). As you know, finding the right balance between performance and resources usage is vital to success.

    I need to configure concurrent consumers from a topic, in order to avoid a bottleneck while processing each received message. Lets say I need 10 consumers, so I could set "concurrency=10" in the listener, and change the CachingConnectionFactory session_cache_size to 10, to guarantee one TCP connection per consumer.

    Is this approach OK? Is there any other parameter I should keep in mind?

    Thanks and congrats!!!

  13. Hi Manu and thanks! 🙂

    Setting the "concurrency" property to the listener container is the way to set multiple concurrent consumers. You can also specify a value of min-max to let Spring dynamically scale it up when message load increases. However, as stated in the reference, it is recommended to keep this value to 1 when using topics, since it may lead to receiving the same message multiple times (all consumers subscribed to a topic will receive each message).

    If message order is not important in your scenario, I think you could consider using a queue with concurrent consumers.

  14. Hi. Thanks for the good job.

    I could'not see the difference in configuration between sync and async delivery. What make exactly in the delivery async in your code ?

    Thanks in advance

  15. Hi, any tips is appreciated.
    I have the following error on my Eclipse application using Spring 3.2.13:

    WARN 2016-04-22 15:58:07,108 [alerts_message_receiver_container-1] DefaultMessageListenerContainer: Setup of JMS me
    ssage listener invoker failed for destination 'alerts' – trying to recover. Cause: Object org.apache.qpid.
    client.AMQSession has been closed
    INFO 2016-04-22 15:58:07,114 [alerts_message_receiver_container-1] AMQConnection: Connection 2 now connected from

    bean id="alerts_jmsConnectionFactory" class="org.apache.qpid.client.AMQConnectionFactory">
    value="amqp://guest:guest@/test?brokerlist='tcp://${}:${jms.port}?retries=9999&connectdelay=30000'&connecttimeout='5000'&maxprefetch=10" />

    bean id="alerts_jmsCachedConnectionFactory"
    property name="targetConnectionFactory" ref="alerts_jmsConnectionFactory" />
    property name="sessionCacheSize" value="3" />

    bean id="alerts_destination" class="org.apache.qpid.client.AMQTopic">

    bean id="alerts_messageProducer"
    property name="jmsTemplate" ref="alerts_jmsTemplate" />

    bean id="alerts_jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    property name="connectionFactory" ref="alerts_jmsCachedConnectionFactory" />
    property name="defaultDestination" ref="alerts_destination" />
    property name="SessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE" />
    property name="sessionTransacted" value="true" />

    bean id="defaultMessageReceiver"
    class="message.receivers.DefaultMessageReceiver" />

    bean id="alerts_message_receiver_container"
    property name="connectionFactory" ref="alerts_jmsCachedConnectionFactory" />
    property name="destinationName" value="${alerts.topic}" />
    property name="messageListener" ref="defaultMessageReceiver" />

Leave a Reply

Your email address will not be published. Required fields are marked *