Skip to content

JMS with Spring Boot & Apache Camel

Furkan Kürşat Danışmaz edited this page Sep 11, 2018 · 5 revisions

Source Folder: jms-camel

Tech Stack:

  • Spring Boot
  • Apache ActiveMQ
  • Apache Camel
  • log4j2 (slf4j impl)
  • project lombok

This is a ready-to-use Maven Java project template with the above tech stack.

Problems Solved

  • Sending & Receiving messages from a message queue
  • Implementing Camel Routes

Let’s start with JMS. What is JMS and what is it used for?

JMS is simply a Java messaging API for software components and it is mainly used for sending/receiving messages from one application to/from another.

Advantages of Using JMS

  • JMS is asynchronous. Clients don’t need to ask whether there is a message that they are subscribed to. They will be notified instead when a message is ready.
  • JMS is reliable since it provides “guaranteed message delivery”.

There are 2 kinds of Messaging Model in JMS

  • Point to Point Model
  • Publish/Subscribe Model

With P2P model, messages sent by the “provider” is put into a named queue. A client listening that specific queue receives the message automatically. (Note that the code provided in this story is an example of this model)

With Pub/Sub model on the other hand, the provider sends messages to a specific “topic” (careful, not queue this time) and all subscribers which are registered to that specific “topic” automatically receive those messages.

Message Oriented Middleware

MoMs are 3rd party products (or platform or middleware) that enable different software components to communicate via message sharing.

JMS is one standard to communicate with MoMs that support JMS (like Apache ActiveMQ).

Apache Camel

Camel is an open-source integration framework that has several components for guess what… “integration” (implementations of Enterprise Integration Patterns). By defining very simple routes we can integrate different software components and make them communicate with each other.

A Simple Example

See the "/java/jms" for a working example.

This example shows how to create a Camel route and receive messages from a specific ActiveMQ queue using Spring-Boot and JMS. Therefore, you need to install Apache ActiveMQ before testing this code on your own (http://activemq.apache.org/download.html)

Here is the POM.xml and required dependencies:

<project ...

    <groupId>...
    <artifactId>...
    <version>...

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring-boot-starter</artifactId>
            <version>2.22.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-jms</artifactId>
            <version>2.22.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    ...

</project>

Below is the JMS configuration

import org.apache.camel.component.jms.JmsComponent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.JmsTransactionManager;

import javax.jms.ConnectionFactory;

@Configuration
public class JmsConfig {

    @Bean
    public JmsTransactionManager jmsTransactionManager(final ConnectionFactory connectionFactory) {
        JmsTransactionManager jmsTransactionManager = new JmsTransactionManager();
        jmsTransactionManager.setConnectionFactory(connectionFactory);
        return jmsTransactionManager;
    }

    @Bean
    public JmsComponent jmsComponent(final ConnectionFactory connectionFactory,
                                     final JmsTransactionManager jmsTransactionManager) {
        JmsComponent jmsComponent = JmsComponent.jmsComponentTransacted(connectionFactory, jmsTransactionManager);
        return jmsComponent;
    }
}

And here is a sample Camel Route:

import lombok.extern.slf4j.Slf4j;
import org.apache.camel.LoggingLevel;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class JmsSampleRouter extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        System.out.println("Configuring route");

        from("{{input.queue}}")
                .log(LoggingLevel.DEBUG, log, "New message received")
                .process(exchange -> {
                    String convertedMessage = exchange.getMessage().getBody() + " is converted";
                    exchange.getMessage().setBody(convertedMessage);
                })
                .to("{{output.queue}}")
                .log(LoggingLevel.DEBUG, log, "Message sent to the other queue")
        .end();

    }
}

Finally, below is the required configuration:

spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=10

max.concurrent.consumers=2

input.queue=jms:MYINPUTQUEUE
output.queue=jms:MYPUTPUTQUEUE

Spring-boot has several ActiveMQ configurations by default which we can override by defining them in our own “application.properties” file. For example, we can enable pooled connection to improve performance with the following two configuration properties:

spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=100

“input.queue” and “output.queue” on the other hand are my own configuration properties which have corresponding queue names that I’ve created in my ActiveMQ.

Now, let’s read the route again from the start:

  • Whenever a message is received from the queue named “MyInputQueue” (the value of “{{input.queue}}”) write a log “New message received”
  • Then, process the message and set the body of the message to the converted message.
  • Send the message to the “MyOutputQueue” (value of “{{output.queue}}”)
  • Finally, write a log “Message sent to the output queue”

That’s it. I hope this helps you with the basics.

Clone this wiki locally