Durable Subscription with JMS and Spring Boot

blog-post-img

When using the publish-subscribe domain with JMS we often want to use durable subscriptions. But how can this be done with Spring Boot? This guide explores their implementation within Spring Boot applications.

What is JMS?

The Java Message Service (JMS) API is a standard for creating, sending, receiving, and reading messages. It enables distributed communication that is loosely coupled, reliable, and asynchronous.

JMS supports two message delivery modes: Point-to-Point and Publish/Subscribe

In the point-to-point domain, a producer can send a message to one consumer through a destination called “queue”. A given queue may have multiple receivers, but only one receiver may consume each message.


In the publish-subscribe domain, a producer can send a message to many consumers through a destination called “topic”. Consumers can subscribe to a topic and receive a copy of each message.

Using Durable Subscriptions

Durable subscriptions allow messages to remain on a topic while the message consumer is not active. A durable subscriber registers a durable subscription by specifying a unique identity that is retained by the JMS provider. You establish the unique identity of a durable subscriber by setting the following:

– A client ID for the connection
– A topic and a subscription name for the subscriber

Configuration Durable Subscriptions with Spring Boot and JMS

The first thing to configure is that we want to use the publish-subscribe domain:

spring.jms.pub-sub-domain=true

Next we must configure durable subscription. Unfortunately this cannot be done using a simple property. We have to configure the ConnectionFactory manually:

@Bean
public JmsListenerContainerFactory<?> artemisConnectionFactory(CachingConnectionFactory connectionFactory,
                                                  DefaultJmsListenerContainerFactoryConfigurer configurer) {
    // When using durable subscription the ClientId must be set for reconnect
    // Note that client IDs need to be unique among all active Connections of the underlying JMS provider
    connectionFactory.setClientId(clientId);

    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    configurer.configure(factory, connectionFactory);
    factory.setPubSubDomain(pubSubDomain);
    factory.setSubscriptionDurable(true);

    return factory;
}

The crucial lines in the configuration are line 6, where we set a client ID, which has to be unique among all active connections, and line 11, where we activate the durable subscription mode.

Finally, we must configure the Listener to use this connection factory by setting the containerFactory attribute of the JmsListener annotation. We also set the subscription. If this attribute is not set, Spring JMS will generate a subscription name based on the class and method name.

@JmsListener(destination = "${chat.topic}",
             selector = "user <> '${chat.user}'",
             containerFactory = "artemisConnectionFactory",
             subscription = "chat")
public void onMessage(Message message) {
    ...
}

Example Code and References

You can find the source code on GitHub: https://github.com/simasch/spring-boot-jms-pubsub-durable

The two pictures are taken from the Java EE 5 tutorial

Have Questions? Let’s Talk

Ready to leverage durable subscriptions in your Spring Boot applications? If you’d like to discuss it further or have any questions, feel free to contact me.

Related Posts

Simon Martinelli
Follow Me