In this tutorial, you will learn how to use RabbitMQ broker in the Spring boot application to send and receive JSON messages between the Producer and the Consumer.
Note that we are going to use Spring boot 3 and JDK 17 or later versions for this tutorial.
What is RabbitMQ?
RabbitMQ is a message queue software (message broker/queue manager) that acts as an intermediary platform where different applications can send and receive messages.
RabbitMQ originally implements the Advanced Message Queuing Protocol (AMQP). But now RabbitMQ also supports several other API protocols such as STOMP, MQTT, and HTTP.
Learn more about RabbitMQ at RabbitMQ Java Tutorial with Examples.
Spring AMQP
The Spring AMQP project applies core Spring concepts to the development of AMQP-based messaging solutions. It provides a "template" as a high-level abstraction for sending and receiving messages.
The Spring AMQP project consists of two parts; spring-amqp is the base abstraction, and spring-rabbit is the RabbitMQ implementation.
Features
- Listener container for asynchronous processing of inbound messages
- RabbitTemplate for sending and receiving messages
- RabbitAdmin for automatically declaring queues, exchanges, and bindings
Spring Boot RabbitMQ Producer and Consumer JSON Message Workflow
The Producer is an application that sends messages to the RabbitMQ broker and the Consumer is an application that reads messages from the RabbitMQ broker.
In this tutorial, we will implement below Spring Boot RabbitMQ flow:
Prerequisites
1. Create and Setup Spring Boot Project in IntelliJ
2. Maven Dependencies
Here is the complete pom.xml file for your reference:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>net.javaguides</groupId>
<artifactId>springboot-rabbitmq-tutorial</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-rabbitmq-tutorial</name>
<description>Demo project for Spring Boot and RabbitMQ</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
</project>
3. Project Structure
4. Connect Spring Boot Application with RabbitMQ
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
5. Configure RabbitMQ in Spring Boot Application
package net.javaguides.springboot.config;
import org.springframework.amqp.core.*;
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("${rabbitmq.queue.json.name}")
private String jsonQueue;
@Value("${rabbitmq.exchange.name}")
private String exchange;
@Value("${rabbitmq.routing.json.key}")
private String routingJsonKey;
// spring bean for queue (store json messages)
@Bean
public Queue jsonQueue(){
return new Queue(jsonQueue);
}
// spring bean for rabbitmq exchange
@Bean
public TopicExchange exchange(){
return new TopicExchange(exchange);
}
// binding between json queue and exchange using routing key
@Bean
public Binding jsonBinding(){
return BindingBuilder
.bind(jsonQueue())
.to(exchange())
.with(routingJsonKey);
}
@Bean
public MessageConverter converter(){
return new Jackson2JsonMessageConverter();
}
@Bean
public AmqpTemplate amqpTemplate(ConnectionFactory connectionFactory){
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(converter());
return rabbitTemplate;
}
}
@Bean
public MessageConverter converter(){
return new Jackson2JsonMessageConverter();
}
@Bean
public AmqpTemplate amqpTemplate(ConnectionFactory connectionFactory){
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(converter());
return rabbitTemplate;
}
The application.properties file change
rabbitmq.exchange.name=javaguides_exchange
rabbitmq.queue.json.name=javaguides_json
rabbitmq.routing.json.key=javaguides_routing_json_key
6. Create POJO Class to Serialize/Deserialize
package net.javaguides.springboot.dto;
import lombok.Data;
@Data
public class User {
private int id;
private String firstName;
private String lastName;
}
7. Create RabbitMQ Producer
We are going to use RabbitTemplate to convert and send a message using RabbitMQ. It is a helper class, like many other Template classes existing in Spring (such as JdbcTemplate, KafkaTemplate, etc).package net.javaguides.springboot.publisher;
import net.javaguides.springboot.dto.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class RabbitMQJsonProducer {
@Value("${rabbitmq.exchange.name}")
private String exchange;
@Value("${rabbitmq.routing.json.key}")
private String routingJsonKey;
private static final Logger LOGGER = LoggerFactory.getLogger(RabbitMQJsonProducer.class);
private RabbitTemplate rabbitTemplate;
public RabbitMQJsonProducer(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void sendJsonMessage(User user){
LOGGER.info(String.format("Json message sent -> %s", user.toString()));
rabbitTemplate.convertAndSend(exchange, routingJsonKey, user);
}
}
public void sendJsonMessage(User user){
LOGGER.info(String.format("Json message sent -> %s", user.toString()));
rabbitTemplate.convertAndSend(exchange, routingJsonKey, user);
}
8. Create REST API to Send JSON Message
package net.javaguides.springboot.controller;
import net.javaguides.springboot.dto.User;
import net.javaguides.springboot.publisher.RabbitMQJsonProducer;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1")
public class MessageJsonController {
private RabbitMQJsonProducer jsonProducer;
public MessageJsonController(RabbitMQJsonProducer jsonProducer) {
this.jsonProducer = jsonProducer;
}
@PostMapping("/publish")
public ResponseEntity<String> sendJsonMessage(@RequestBody User user){
jsonProducer.sendJsonMessage(user);
return ResponseEntity.ok("Json message sent to RabbitMQ ...");
}
}
Test REST API using Postman
http://localhost:8080/api/v1/publish
JSON payload:
{
"id": 1,
"firstName": "Ramesh",
"lastName": "Fadatare"
}
9. Create RabbitMQ Consumer
package net.javaguides.springboot.consumer;
import net.javaguides.springboot.dto.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
public class RabbitMQJsonConsumer {
private static final Logger LOGGER = LoggerFactory.getLogger(RabbitMQJsonConsumer.class);
@RabbitListener(queues = {"${rabbitmq.queue.json.name}"})
public void consumeJsonMessage(User user){
LOGGER.info(String.format("Received JSON message -> %s", user.toString()));
}
}
We configure consumers using the @RabbitListener annotation. The only argument passed here is the queues' name. Consumers are not aware here of exchanges or routing keys.
The @RabbitListener will trigger a logic inside Spring to find a converter from JSON to that specific class.
9. Demo
Check Console Logs:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.0.0-SNAPSHOT)
2022-07-05T16:58:49.754+05:30 INFO 10037 --- [ main] .s.SpringbootRabbitmqTutorialApplication : Starting SpringbootRabbitmqTutorialApplication using Java 17.0.2 on Rameshs-MacBook-Air.local with PID 10037 (/Users/rameshfadatare/Downloads/springboot-rabbitmq-tutorial/target/classes started by rameshfadatare in /Users/rameshfadatare/Downloads/springboot-rabbitmq-tutorial)
2022-07-05T16:58:49.756+05:30 INFO 10037 --- [ main] .s.SpringbootRabbitmqTutorialApplication : No active profile set, falling back to 1 default profile: "default"
2022-07-05T16:58:50.314+05:30 INFO 10037 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-07-05T16:58:50.318+05:30 INFO 10037 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-07-05T16:58:50.319+05:30 INFO 10037 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.0.21]
2022-07-05T16:58:50.366+05:30 INFO 10037 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-07-05T16:58:50.367+05:30 INFO 10037 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 588 ms
2022-07-05T16:58:50.652+05:30 INFO 10037 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2022-07-05T16:58:50.654+05:30 INFO 10037 --- [ main] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [localhost:5672]
2022-07-05T16:58:50.716+05:30 INFO 10037 --- [ main] o.s.a.r.c.CachingConnectionFactory : Created new connection: rabbitConnectionFactory#6d1dcdff:0/SimpleConnection@4f654cee [delegate=amqp://guest@127.0.0.1:5672/, localPort= 62983]
2022-07-05T16:58:50.785+05:30 INFO 10037 --- [ main] .s.SpringbootRabbitmqTutorialApplication : Started SpringbootRabbitmqTutorialApplication in 1.43 seconds (process running for 1.637)
2022-07-05T16:58:59.853+05:30 INFO 10037 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-07-05T16:58:59.853+05:30 INFO 10037 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2022-07-05T16:58:59.854+05:30 INFO 10037 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
2022-07-05T16:58:59.909+05:30 INFO 10037 --- [nio-8080-exec-1] n.j.s.publisher.RabbitMQJsonProducer : Json message sent -> User(id=1, firstName=Ramesh, lastName=Fadatare)
2022-07-05T16:58:59.954+05:30 INFO 10037 --- [ntContainer#1-1] n.j.s.consumer.RabbitMQJsonConsumer : Received JSON message -> User(id=1, firstName=Ramesh, lastName=Fadatare)
Udemy Course
Conclusion
In this tutorial, we have seen how to use RabbitMQ broker in the Spring boot application to send and receive JSON messages between the Producer and the Consumer.
Comments
Post a Comment
Leave Comment