Virtual Destinations allow us to create logical destinations that map onto one or more physical destinations.
Virtual Destinations are logical destinations, a combination of Queues or Topics that map onto one or more physical destinations. It provides loosely coupled messaging configurations and especially helps when an application is running on multiple instances.
In this article, we will look at how virtual destinations work in ActiveMQ with the help of a simple Spring Boot application.
Prerequisites
Install Apache ActiveMQ by downloading the installer from the official website. The guide to installing ActiveMQ on various operating systems is described here.
Create a simple Spring Boot application and add the following dependency in pom.xml. This dependency is for JMS messaging using ActiveMQ.
org.springframework.boot spring-boot-starter-activemq
Virtual Topics
The concept of virtual topics is that producers send to a topic in the usual JMS way but the topic is virtual. The listeners can consume from their own queue or via logical topic subscription.
ActiveMQ will copy and duplicate each message from the topic to the consumer queues.
JMS Producer
We are going to write a simple producer which will create a virtual topic and publish a message on that topic.
@Component public class JMSProducer { private final JmsTemplate jmsTemplate; public JMSProducer(final JmsTemplate jmsTemplate) { this.jmsTemplate = jmsTemplate; } public void createVirtualTopicAndPublishMessage() { jmsTemplate.convertAndSend(new ActiveMQTopic("VirtualTopic.medium"), "Test virtual topic"); } }
Notice that topic name is “VirtualTopic.medium”. The default naming convention for virtual topics in ActiveMQ starts with a prefix “VirtualTopic.>”. However, we can customize these names by configuring in ActiveMQ broker configuration.
JMS Consumer
We are now going to write a consumer to listen to a queue to receive the message that will be published on the virtual topic.
@Component public class JMSConsumer { private static final Logger LOGGER = LoggerFactory.getLogger(JMSConsumer.class); @JmsListener(destination = "Consumer.app.VirtualTopic.medium") public void readMessage(final TextMessage message) { LOGGER.info("Received message {}", message); } }
The queue name is named with the convention “Consumer.[clientName].VirtualTopic.>” which is the default convention for queues that are associated with virtual topics.
Any message that is published on virtual topic “VirtualTopic.medium” will be copied to the queue “Consumer.app.VirtualTopic.medium”.
Testing the Sample Application
Let’s write a simple command line runner class which will be used to publish the message on application start up.
@Component public class AppCommandLineRunner implements CommandLineRunner { private final JMSProducer jmsProducer; public AppCommandLineRunner(final JMSProducer jmsProducer) { this.jmsProducer = jmsProducer; } @Override public void run(String... args) { jmsProducer.createVirtualTopicAndPublishMessage(); } }
Run the application and we will see the topic and queue being created in ActiveMQ console. We can navigate to ActiveMQ console at http://localhost:8161/admin/index.jsp.
We should be able to see the virtual topic in topics view.
We will also see the queue in queues view. If the application has run successfully, then we will see one message being enqueued and dequeued.
Customizing Configuration
As I mentioned before, the naming convention can be customized via broker configuration. This can be done by modifying activemq.xml file.
It allows you to not only customize names but also to turn on the selector awareness which is de-activated by default. The selector awareness can be used to selectively forward the messages to different destinations.
Conclusion
We can add as many consumers as we need using virtual topics without modifying ActiveMQ broker configuration.
I hope this article has helped you gain an understanding on virtual destinations. Read more at https://activemq.apache.org/virtual-destinations.
Leave a Reply