Open In App

Spring – JMS Integration

JMS is a standard Java API that allows a Java application to send messages to another application. It is highly scalable and allows us to loosely couple applications using asynchronous messaging. Using JMS we can read, send, and read messages.

Benefits of using JMS with Spring Integration

Here are some implementations of JMS is as follows: 



JMS Message 

 A JMS message can be divided into three parts that are as follows:  

Implementation

Here we will be building a sample greeting (Maven-based) application to demonstrate how to integrate and use JMS. For simplicity, we will be using an embedded server instead of creating another application.



The project Structure is as follows:  

Step 1: Create a spring project using spring initializer. Create the folders and files as depicted in the below image as follows: 

Step 2: Add the below dependencies to pom.xml file.




<dependency>
           <groupId>org.apache.activemq</groupId>
           <artifactId>artemis-server</artifactId>
       </dependency>
       <dependency>
           <groupId>org.apache.activemq</groupId>
           <artifactId>artemis-jms-server</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-artemis</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
 
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-devtools</artifactId>
           <scope>runtime</scope>
           <optional>true</optional>
       </dependency>
       <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
           <optional>true</optional>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>

Model Layer

Step 3: Create a simple POJO (Plain old java class) which will act as our model for sending and receiving messages. Here we have used Lombok to reduce boilerplate code. Annotations used are as follows:

Example:




// Java Program to Illustrate Model Layer
 
package com.anuanu.springjms.model;
 
// Importing required classes
import java.io.Serializable;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
 
// Annotation
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
 
// Class
// Implementing Serializable interface
public class GreetingMessage implements Serializable {
 
    // Class data members
    static final long serialVersionUID
        = -7462433555964441775L;
    private UUID id;
    private String message;
}

Required Configurations is as follows: 

A. Embedded Server Configuration

As discussed earlier, we will be creating an embedded server for the demonstration of JMS messaging. We will be using ActiveMQServers to create our embedded server. Here is the method signature to newActiveMQServer:

Modifier and Type Methods and Description
static ActiveMQServer newActiveMQServer (Configuration config)

Note: Configuration can be changed as per the requirement.

The embedded server also starts when our spring boot application starts. (as we have called start() method on the server).

Example:




// Java Program to Illustrate Embedded Server Configuration
 
package com.anuanu.springjms;
 
// Importing required classes
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ActiveMQServers;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class SpringJmsApplication {
 
    // Main driver method
    public static void main(String[] args) throws Exception
    {
 
        // Embedded Server Configuration
        ActiveMQServer activeMQServer
            = ActiveMQServers.newActiveMQServer(
                new ConfigurationImpl()
                    .setPersistenceEnabled(false)
                    .setJournalDirectory(
                        "target/data/journal")
                    .setSecurityEnabled(false)
                    .addAcceptorConfiguration("invm",
                                              "vm://0"));
 
        activeMQServer.start();
        SpringApplication.run(SpringJmsApplication.class,
                              args);
    }
}

B. Task Configuration

The taskConfig class will help us execute tasks asynchronously. The task here is sending messages at fixed intervals of time. For sending messages at fixed intervals we have enabled the scheduler using @EnableScheduling annotation. Annotations used are as follows: 

Example:




// Java Program to Illustrate Task Configuration
 
package com.anuanu.springjms.config;
 
// Importing required classes
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
 
// Annotations
@EnableScheduling
@EnableAsync
@Configuration
 
// Class
public class TaskConfig {
 
    // Task Configuration
    @Bean TaskExecutor taskExecutor()
    {
        return new SimpleAsyncTaskExecutor();
    }
 
    // taskExecutor bean is injected into spring context,
    // and spring will use it to execute tasks for us
}

C. Message Converter Configuration

The jmsConfig class provides a common stream for producers and consumers for producing and consuming messages respectively. It also provides a bean for converting Java objects and JMS messages. Annotations used are as follows:

Note: Message converter uses Jackson 2.x to convert messages to and from JSON.  It maps an object to a BytesMessage, or to a TextMessage if the targetType is set to MessageType.TEXT.  It converts from a TextMessage or BytesMessage to an object.

Example:




// Java Program to Illustrate Task Configuration
 
package com.anuanu.springjms.config;
 
// Importing required classes
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
 
// Annotations
@Configuration
 
// Class
public class JmsConfig {
 
    // Class data member
    public static final String QUEUE = "greet";
 
    // Annotation
    @Bean
 
    // Class
    public MessageConverter messageConverter()
    {
 
        MappingJackson2MessageConverter converter
            = new MappingJackson2MessageConverter();
        converter.setTargetType(MessageType.TEXT);
        converter.setTypeIdPropertyName("_type");
 
        return converter;
    }
 
    // Enabling spring to take jms messages and flip it
    // to a json message. then it can read
    // that jms message as a jms text message and
    // convert it back to java object
}

Sending JMS Messages

The MessageSender class (described below) is mainly used to create and produce/send messages to the common stream from where the consumer can consume messages. We have used JmsTemplate which is a  helper class that makes it easier for us to receive and send messages through JMS. We have also annotated the class with @Scheduled with a value of 2000 ms which tells the scheduler to send the messages at an interval of every 2 seconds. Annotations used are as follows: 

Example:




// Java Program to Illustrate Sending JMS Messages
 
package com.anuanu.springjms.sender;
 
// Importing required classes
import com.anuanu.springjms.config.JmsConfig;
import com.anuanu.springjms.model.GreetingMessage;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
// Annotations
@RequiredArgsConstructor
@Component
 
// Class
public class MessageSender {
 
    // Class data member
    private final JmsTemplate jmsTemplate;
    private static Integer ID = 1;
 
    // Annotation
    @Scheduled(fixedRate = 2000)
 
    // Method
    public void sendMessage()
    {
        // Display command
        System.out.println("Greetings user");
 
        GreetingMessage message
            = GreetingMessage.builder()
                  .id(UUID.randomUUID())
                  .message("Greetings user " + ID++)
                  .build();
 
        jmsTemplate.convertAndSend(JmsConfig.QUEUE,
                                   message);
 
        // Display command
        System.out.println("Message sent!!!");
    }
}

Receiving JMS Messages

The MessageListener class (described below) acts as a consumer i.e. it consumes/receives messages that reside in the common stream and is not already consumed. The location of the common stream “JmsConfig.QUEUE” is passed to the destination method in @JmsListener. Annotations used are as follows: 

Example:




// Java Program to Illustrate Receiving JMS Messages
 
package com.anuanu.springjms.listener;
 
// Importing required classes
import com.anuanu.springjms.config.JmsConfig;
import com.anuanu.springjms.model.GreetingMessage;
import javax.jms.Message;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
 
// Annotation
@Component
 
// Class
public class MessageListener {
 
    @JmsListener(destination = JmsConfig.QUEUE)
 
    public void
    listen(@Payload GreetingMessage greetingMessage,
           @Headers MessageHeaders messageHeaders,
           Message message)
    {
 
        // Display command
        System.out.println("Greeting Received!!!");
 
        System.out.println(greetingMessage);
    }
}

Output: 

The message is sent and received every 2 seconds. A unique username and id is passed for every new message.

Inspecting the messageListener class:

The below image shows us the jms message that is received at the messageListener class. There is a variety of properties that can be customized in the header field. Notice the one key-value pair we added in the header.

'_type' -> 'com.anuanu.springjms.model.GreetingMessage'


Article Tags :