Integrating RabbitMQ with SpringBoot Application (Sender Part)
Making your spring API asynchronous adds up to the crucial features of an application. Asynchronous calls to a spring API means less burden on the server as well as no high demand from application to respond instantly.
There are many ways to make your spring API as asynchronous which includes the usage of RabbitMQ, Kafka, and ActiveMQ, etc. RabbitMQ, Kafka, and ActiveMQ are all messaging technologies used to provide asynchronous communication and decouple processes (detaching the sender and receiver of a message). They are called message queues, message brokers, or messaging tools.
Today, we will be using RabbitMQ to make our spring API asynchronous.
RabbitMQ is open-source message-broker software that originally implemented the Advanced Message Queuing Protocol. RabbitMQ is a queue management tool that works on the principle of “FIFO” (First in First out). Rabbit processes all the incoming messages from itself before forwarding it to server or application. In case, application/server is down, Rabbit will store the incoming messages in it unless the application/server is back up and running. For installation purpose, you can refer to https://cmatskas.com/getting-started-with-rabbitmq-on-windows/
Implementation of RabbitMQ with Java-springBoot application.
The initial requirement for the implementation is 2 sample spring projects out which, one can act as the sender of messages and the other one can act as a receiver. So, go to https://start.spring.io/ and create a maven project with desired dependencies. For convenience, name it sender. Go ahead and import this in eclipse.
Designing pom.xml
Add the following dependency in the pom.xml file.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
This jar is required to access features of “Queue”. Ampq dependency helps in the creation of queues and exchanges in Rabbit.
Designing application.properties file
This file resides in the resources folder of the application. In our case it will be at sender>src>main>resources>application.properties
This file should have the configuration information of RabbitMQ such as HostName, port, username, password, etc. Below is the snapshot of how it will look after configuration.
Host and Port refer to the server Rabbit is running on. Username & Password as name clarifies is the credentials of Rabbit to log on. Exchange, Queue and Routing Key values are also declared. Read more about what is Exchange, Queue and routing key at https://www.rabbitmq.com/tutorials/amqp-concepts.html
Configuration file for Rabbit (RabbitMQConfig)
Moving on, we make a configuration file, to configure and use queues and exchanges. Also, this configuration contains a message converter, that converts the message input to a passable format to queue.
Below is the code that will be in the configuration file.
package com.sender.sender.config;import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {
@Value("${sample.rabbitmq.queue}")
String queueName;@Value("${sample.rabbitmq.exchange}")
String exchange;@Value("${sample.rabbitmq.routingkey}")
private String routingkey;@Bean
Queue queue() {
return new Queue(queueName, false);
}@Bean
DirectExchange exchange() {
return new DirectExchange(exchange);
}@Bean
Binding binding(Queue queue, DirectExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(routingkey);
}@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}@Bean
public AmqpTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(jsonMessageConverter());
return rabbitTemplate;
}
}
The package structure looks like :
Creating controller and service
The final step is to make a controller that accepts custom messages from the user and passes it on to service class. Service class binds that message and sends it to Rabbit queue.
Controller.java
package com.sender.sender.controller;import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.sender.sender.service.RabbitMQSender;@RestController
@RequestMapping(value = "/rabbitmq/")
public class Controller {@Autowired
RabbitMQSender rabbitMQSender;
@PostMapping(value = "/producer")
public String producer(@RequestParam(value="message") String message) throws IOException {
rabbitMQSender.send(message);
return "Message sent to the RabbitMQ Successfully";
}
}
Service.java
package com.sender.sender.service;import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;@Service
public class RabbitMQSender {@Autowired
private AmqpTemplate rabbitTemplate;
@Value("${sample.rabbitmq.exchange}")
private String exchange;
@Value("${sample.rabbitmq.routingkey}")
private String routingkey;
@Scheduled
public void send(String message) {
String CustomMessage = "This is a message from sender"+ message;
rabbitTemplate.convertAndSend(exchange, routingkey, CustomMessage);
System.out.println("Send msg to consumer= " + CustomMessage+" ");
}
}
Lets send some messages
On the start of the application server, and hitting API https://localhost:8002/rabbitmq/producer with parameter as a custom message. A queue is generated automatically at Rabbit server that holds the sent messages. As currently, we are only sending the messages and not receiving it anywhere, the messages will be residing in RabbitMQ. Below is a snapshot of the generated queue at Rabbit holding some messages.
So this is how we use Spring Boot integrated with RabbitMQ to make asynchronous calls.
Further, the receiver part is discussed at https://medium.com/@nerengenbabu/integrating-rabbitmq-with-springboot-application-reciever-part-ad8b0f90cdb9/ .