Enterprise Java

Configure a Spring JMS application with Spring Boot and annotation support

1. Introduction

In previous posts we learned how to configure a project using Spring JMS. If you check the article introduction to messaging with Spring JMS, you will notice that it is configured using XML. This article will take advantage of the improvements introduced in Spring 4.1 version, and configure a JMS project using Java config only.

In this example we will also see how easy it can be to configure the project by using Spring Boot.

Before we get started, just note that as usual, you can take a look at the source code of the project used in the examples below.

See the example project at github.

Sections:

  1. Introduction.
  2. The example application.
  3. Setting up the project.
  4. A simple example with JMS listener.
  5. Sending a response to another queue with @SendTo.
  6. Conclusion.

2. The example application

The application uses a Client service to send orders to a JMS queue, where a JMS listener will be registered and handle these orders. Once received, the listener will store the order through the Store service:

jms_diagram

We will use the Order class to create orders:

public class Order implements Serializable {
    private static final long serialVersionUID = -797586847427389162L;
    
    private final String id;
    
    public Order(String id) {
        this.id = id;
    }
    
    public String getId() {
        return id;
    }
}

Before moving on to the first example, we will first explore how the project structure is built.

3. Setting up the project

3.1   Configuring pom.xml

The first thing to do is to define the artifact spring-boot-starter-parent as our parent pom.

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

This parent basically sets several Maven defaults and provides the dependency management for the main dependencies that we will use, like the Spring version (which is 4.1.6).

It is important to note that this parent pom defines the version of many libraries but it does not add any dependency to our project. So don’t worry about getting libraries you won’t use.

The next step is to set the basic dependencies for Spring Boot:

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

In addition to the core Spring libraries, this dependency will bring the auto configuration functionality of Spring Boot. This will allow the framework to try to automatically set up the configuration based on the dependencies you add.

Finally, we will add the Spring JMS dependency and the ActiveMQ message broker, leaving the whole pom.xml as follows:

<groupId>xpadro.spring</groupId>
<artifactId>jms-boot-javaconfig</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>JMS Spring Boot Javaconfig</name>
 
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
 
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <start-class>xpadro.spring.jms.JmsJavaconfigApplication</start-class>
    <java.version>1.8</java.version>
    <amq.version>5.4.2</amq.version>
</properties>
 
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jms</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-core</artifactId>
        <version>${amq.version}</version>
    </dependency>
</dependencies>
 
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

3.2   Spring Configuration with Java Config

The configuration class just needs to configure an embedded message broker. The rest is auto configured by Spring Boot:

@SpringBootApplication
public class JmsJavaconfigApplication {
    private static final String JMS_BROKER_URL = "vm://embedded?broker.persistent=false,useShutdownHook=false";
    
    @Bean
    public ConnectionFactory connectionFactory() {
        return new ActiveMQConnectionFactory(JMS_BROKER_URL);
    }
    
    public static void main(String[] args) {
        SpringApplication.run(JmsJavaconfigApplication.class, args);
    }
}

We used @SpringBootApplication instead of the usual @Configuration annotation. This Spring Boot annotation is also annotated with @Configuration. In addition, it sets other configuration like Spring Boot auto configuration:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {

It is all set now. We will see how to configure a JMS listener in the example in the next section, since it is configured with an annotation.

4. A simple example with JMS listener

4.1   Sending an order to a JMS queue

The ClientService class is responsible for sending a new order to the JMS queue. In order to accomplish this, it uses a JmsTemplate:

@Service
public class ClientServiceImpl implements ClientService {
    private static final String SIMPLE_QUEUE = "simple.queue";
    
    private final JmsTemplate jmsTemplate;
    
    @Autowired
    public ClientServiceImpl(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }
    
    @Override
    public void addOrder(Order order) {
        jmsTemplate.convertAndSend(SIMPLE_QUEUE, order);
    }
}

Here, we use a JmsTemplate to convert our Order instance and send it to the JMS queue. If you prefer to directly send a message through the send message, you can instead use the new JmsMessagingTemplate. This is preferable since it uses the more standardized Message class.

4.2   Receiving an order sent to the JMS queue

Registering a JMS listener to a JMS listener container is as simple as adding the @JmsListener annotation to the method we want to use. This will create a JMS listener container under the covers that will receive messages sent to the specified queue and delegate them to our listener class:

@Component
public class SimpleListener {
    private final StoreService storeService;
    
    @Autowired
    public SimpleListener(StoreService storeService) {
        this.storeService = storeService;
    }
    
    @JmsListener(destination = "simple.queue")
    public void receiveOrder(Order order) {
        storeService.registerOrder(order);
    }
}

The StoreService receives the order and saves it to a list of received orders:

@Service
public class StoreServiceImpl implements StoreService {
    private final List<Order> receivedOrders = new ArrayList<>();
    
    @Override
    public void registerOrder(Order order) {
        this.receivedOrders.add(order);
    }
    
    @Override
    public Optional<Order> getReceivedOrder(String id) {
        return receivedOrders.stream().filter(o -> o.getId().equals(id)).findFirst();
    }
}

4.3   Testing the application

Now let’s add a test to check if we did everything correctly:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = JmsJavaconfigApplication.class)
public class SimpleListenerTest {
    
    @Autowired
    private ClientService clientService;
    
    @Autowired
    private StoreService storeService;
    
    @Test
    public void sendSimpleMessage() {
        clientService.addOrder(new Order("order1"));
        
        Optional<Order> storedOrder = storeService.getReceivedOrder("order1");
        Assert.assertTrue(storedOrder.isPresent());
        Assert.assertEquals("order1", storedOrder.get().getId());
    }
}

5. Sending a response to another queue with @SendTo

Another addition to Spring JMS is the @SendTo annotation. This annotation allows a listener to send a message to another queue. For example, the following listener receives an order from the “in.queue” and after storing the order, sends a confirmation to the “out.queue”.

@JmsListener(destination = "in.queue")
@SendTo("out.queue")
public String receiveOrder(Order order) {
    storeService.registerOrder(order);
    return order.getId();
}

There, we have another listener registered that will process this confirmation id:

@JmsListener(destination = "out.queue")
public void receiveOrder(String orderId) {
    registerService.registerOrderId(orderId);
}

6. Conclusion

With annotation support, it is now much easier to configure a Spring JMS application, taking advantage of asynchronous message retrieval using annotated JMS listeners.

Xavier Padro

Xavier is a software developer working in a consulting firm based in Barcelona. He is specialized in web application development with experience in both frontend and backend. He is interested in everything related to Java and the Spring framework.
Subscribe
Notify of
guest

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

6 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Xavier Padró
9 years ago

Hi,

ConnectionFactory bean definition is not required. Spring Boot will automatically configure it if you include ActiveMQ library on the classpath. Please, check my blog for the latest update. Thanks!

bryan
bryan
9 years ago

is it possible to do the same with HornetQ?

ravi
ravi
9 years ago

Hi,

I need to integrate Rest with ActiveMQ.

Can you provide me a sample code

Bill
Bill
8 years ago
Reply to  ravi

Is there an example with REST?

Marc Johnen
8 years ago

Thanks for the article, but the link to gitlab is not working, would be nice to have the source code.

DS
DS
7 years ago

thanks for the details.
I am looking for the sample with IBM MQ . also the can you update the working GIT location please

Back to top button