Using ActiveMQ with Apache Camel - with example

How to send and receive messages from an ActiveMQ Artemis message broker using Camel’s JMS component and Spring Boot

Using ActiveMQ with Apache Camel - with example

Tags: ,

Want to use JMS? Apache Camel makes it pretty easy to send and receive messages from any message broker which supports the JMS API.

In this article, I’ll talk about configuring Apache Camel to work with one of the most common message brokers, Apache ActiveMQ. As usual, there’s some example code along the way for you to copy and try out.

What you need

To send and receive messages with Apache Camel and ActiveMQ, you’ll need:

  • An ActiveMQ broker to connect to, to send and receive messages. You can download ActiveMQ from its web site and follow the documentation to run it. Alternatively, you can embed a broker inside your Java application, or run ActiveMQ in a Docker container.

  • An ActiveMQ connection factory configured in your application, which is set up with the right parameters to connect to your ActiveMQ broker. The way to do this varies a lot between different Java platforms and application servers (Spring Boot, OSGi, Wildfly, etc.). But, the main principle is to declare an instance of ActiveMQ’s connection factory object, and give it some properties to connect to your broker, like host, port, etc.

    Spring Boot is a bit of a special case. It will create a ConnectionFactory for you automatically, if certain properties are set. See further below for more info about this.

  • Configure an instance of Camel’s JMS component. This is so that when you use the jms:.... endpoint in your routes, Camel will know which Connection Factory it should use. The usual way of configuring a component in Camel is:

    1. create an instance of the Component object (e.g. JmsComponent jms = new JmsComponent())

    2. set the component’s properties (e.g. jms.setConnectionFactory())

    3. add the component to Camel’s bean registry.

    If you’re using Spring or Spring Boot, then Camel uses your Spring context as a registry. Just define your Camel component as a Spring Bean (e.g. using @Bean, or Spring XML definitions) and Camel will be able to see and use it.

Of course, Apache Camel should also be up and running in your project. I won’t cover Camel set-up in this article, but if you want to read about how to start a new Camel project, then take a look at my other articles:

In this article I’m going to use Apache ActiveMQ Artemis which is the latest generation of ActiveMQ.

Creating the Connection Factory and Camel JMS component

First we need to make sure we have a ConnectionFactory. Camel needs a ConnectionFactory to be able to create connections to your message broker.

A ConnectionFactory is a Java interface for defining objects that will store connection details to message brokers - things like host, port, usernames and passwords.

ActiveMQ Artemis has its own implementation of ConnectionFactory. Simply define an instance of this Artemis connection factory, create an instance of Camel’s JmsComponent, and wire them up together.

For example, in Spring Java configuration:

@Bean
public JmsComponent jmsComponent() throws JMSException {
    // Create the connectionfactory which will be used to connect to Artemis
    ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory();
    cf.setBrokerURL("tcp://localhost:61616");
    cf.setUser("admin");
    cf.setPassword("admin");

    // Create the Camel JMS component and wire it to our Artemis connectionfactory
    JmsComponent jms = new JmsComponent();
    jms.setConnectionFactory(cf);
    return jms;
}

Since I’m defining a Camel JMS component as a Spring bean, Camel will see it, and use it whenever I refer to the JMS component in my routes.

Spring Boot magic explained: connection factories & Camel components

Using Spring Boot? It works a little differently. Due to its convention-over-configuration approach, it will do a bunch of stuff for you.

If you’re wondering why everything seems to work magically out-of-the-box, then here’s why:

🐇 MAGIC TRICK 1 🐇: If you’re using Spring Boot, it can create a ConnectionFactory for you automatically.

Spring Boot will create an ActiveMQ Artemis connection factory, if:

  • it finds the Artemis client libraries on your classpath,

  • and you specify the broker details in properties beginning with spring.artemis.*,

  • and you haven’t already defined a connection factory yourself.

This is explained (briefly) in the Spring Boot docs:

Extract from the Spring Boot documentation showing which properties can be used to configure Artemis connection factory
Spring Boot Artemis messaging properties

🎩 MAGIC TRICK 2 🎩: If you’re using one of Camel’s -starter dependencies, it can create and configure components for you automatically.

If you add camel-jms-starter to your application’s Maven dependencies, then Camel will configure the JMS component automatically – if it can find a ConnectionFactory.

So, in practice, this means that to configure JMS messaging with ActiveMQ Artemis for Camel on Spring Boot, you just need to do 2 things:

  • Add the camel-jms-starter and ActiveMQ client dependencies to Maven.

  • Set the properties spring.artemis.* in your application.properties file.

Using the JMS component in a route

Once you have configured your JMS component and wired it to your connection factory, you can send and receive messages from ActiveMQ by using the jms: endpoint in your routes.

For example, to receive a message from ActiveMQ:

// Receive a message from a queue
from("jms:queue:HELLO.WORLD")
        .log("Received a message - ${body}");

Or, to send a message to ActiveMQ:

// Send a message to a queue every 5 seconds
from("timer:mytimer?period=5000")
        .setBody(constant("HELLO from Camel!"))
        .to("jms:queue:HELLO.WORLD");

With that in mind, let’s look at the example!

Example - connecting to ActiveMQ from Camel using Spring Boot

So now let’s put it all together. Here’s an example of how to add ActiveMQ Artemis JMS messaging capabilities to an Apache Camel project, on Spring Boot:

  1. First, make sure your project imports the Spring Boot and Camel BOMs (Bill-of-Materials). This is done in your Maven POM, and will help us set our version numbers correctly:

    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot BOM -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Camel BOM -->
            <dependency>
                <groupId>org.apache.camel.springboot</groupId>
                <artifactId>camel-spring-boot-dependencies</artifactId>
                <version>${camel.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
  2. Add the Artemis client library, and the Camel JMS component (for Spring Boot) to your Maven POM, like this:

    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>artemis-jms-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.camel.springboot</groupId>
        <artifactId>camel-jms-starter</artifactId>
    </dependency>
    
    • The artemis-jms-client contains the libraries needed to connect to ActiveMQ. When Spring Boot detects this on the classpath, it will create a connection factory to ActiveMQ Artemis.

    • The camel-jms-starter contains Camel’s JMS component. As it is in the springboot package, and it is named -starter, we know it will also do some autoconfiguration for us. In this case, it will automatically configure Camel’s JMS component to use our Artemis connection factory.

    Notice how I’m not specifying the version number of these dependencies; because the Spring Boot and Camel BOMs will set them for us.

  3. Set the Artemis connection properties in your application.properties file. You must use exactly these property names:

    spring.artemis.host=localhost
    spring.artemis.port=61616
    spring.artemis.user=myuser
    spring.artemis.password=mypass
    

    If you’re not using Spring Boot, you will need to do some of this configuration manually. You should create a Connection Factory and then manually wire this to Camel’s JMS component. See a Java example or an XML example.

  4. Define a Camel route which consumes from a queue. Start the route with a From step, using the URL jms:queue:YOUR_QUEUE_NAME.

    In this example, I’m receiving a message from the HELLO.WORLD queue and writing it to a log:

    // Receive a message from a queue
    from("jms:queue:HELLO.WORLD")
        .log("Received a message - ${body}");
    
  5. Define another route to write a message to a queue. Here I’m using a Timer component to trigger sending a message to a queue, every 5 seconds:

    // Send a message to a queue every 5 seconds
    from("timer:mytimer?period=5000")
            .setBody(constant("HELLO from Camel!"))
            .to("jms:queue:HELLO.WORLD");
    
  6. Now make sure your broker is started, and then run your Camel Spring Boot application:

    mvn clean spring-boot:run
    

    And you should see this output in the console log:

    2020-02-01 12:01:17.102 INFO 21743 — [er[HELLO.WORLD]] route2 : Received a message - HELLO from Camel!

Congrats! You’ve now written a Camel application which reads and writes messages to a queue in ActiveMQ!

Just want to see the complete, worked example? Click on the button below to see the completed application:

Get the example code on GitHub

Summary

To send and receive messages to ActiveMQ using Apache Camel, make sure you configure a connection factory, create and configure Camel’s JMS component, and then use the jms: endpoint URI in your Camel routes.

If you’re using Spring Boot, you can skip the connection factory and Camel component configuration by using the right properties (spring.artemis.* or spring.activemq.*) and using Camel’s camel-jms-starter Maven dependency.

Questions? Comments? Do I need to update anything in this article? Let me know your thoughts in the comments section below!

Photo by Shiro Yamamoto on Unsplash  

Comments

What do you think? You can use Markdown in your comment. To write code, indent each line with 4 spaces.