Understanding Virtual Destinations in ActiveMQ with an Example

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.


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.


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.

Virtual Topic and queues

JMS Producer

We are going to write a simple producer which will create a virtual topic and publish a message on that topic.

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.

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.

public class AppCommandLineRunner implements CommandLineRunner {

    private final JMSProducer jmsProducer;

    public AppCommandLineRunner(final JMSProducer jmsProducer) {
        this.jmsProducer = jmsProducer;

    public void run(String... args) {

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.



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

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.