What is RabbitMQ in Spring Boot and how to use it
Introduction
RabbitMQ is an open source message queuing system, which implements message delivery through AMQP (Advanced Message Queuing Protocol). Spring Boot is currently a very popular Java development framework, which provides many convenient functions, including support for RabbitMQ.
In this article, we will introduce the basic concepts of RabbitMQ and how to use RabbitMQ in Spring Boot.
Basic concepts of RabbitMQ
Before using RabbitMQ, we need to understand some basic concepts.
message queue
Message queues are a mechanism for asynchronous communication. The message sender sends the message to the queue, and the message receiver gets the message from the queue. Through the message queue, the asynchronous delivery of messages can be realized, and the coupling between systems can be reduced.
information
A message is the data that needs to be delivered.
producer
A producer is a program that sends messages to a message queue.
consumer
A consumer is a program that obtains and processes messages from a message queue.
queue
A queue is a place where messages are stored.
switch
The exchange is used to receive the message sent by the producer and route the message to the corresponding queue.
routing key
The routing key is a string specifying which queue the message should be routed to.
to bind
Binding refers to the process of connecting queues and exchanges.
How to use RabbitMQ with Spring Boot
add dependencies
First, we need to add RabbitMQ dependency in Maven or Gradle. In Maven, we can add the following dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
In Gradle, we can add the following dependencies:
implementation 'org.springframework.boot:spring-boot-starter-amqp'
Configure RabbitMQ
In Spring Boot, we can use application.yml or application.properties files to configure RabbitMQ.
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
create producer
Here is an example of a simple RabbitMQ producer:
@Component
public class RabbitMQProducer {
private final RabbitTemplate rabbitTemplate;
public RabbitMQProducer(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void send(String message) {
rabbitTemplate.convertAndSend("myExchange", "myRoutingKey", message);
}
}
In this example, we use the RabbitTemplate class provided by Spring AMQP to send messages. convertAndSend
method is used to send a message to the specified exchange and routing key.
create consumer
Here is an example of a simple RabbitMQ consumer:
@Component
public class RabbitMQConsumer {
@RabbitListener(queues = "myQueue")
public void receive(String message) {
System.out.println("Received message: " + message);
}
}
In this example, we use @RabbitListener
the annotations provided by Spring AMQP to specify which queue the consumer should listen to. When a message arrives on the queue, receive
the method will be called, and the content of the received message will be passed to the method as a parameter.
Run the example
We have now created a simple RabbitMQ application. We can create Spring Boot application in main method and inject our producer and consumer in it. Then, we can use the producer to send messages to the queue, and the consumer will receive these messages and output them to the console.
@SpringBootApplication
public class Application implements CommandLineRunner {
private final RabbitMQProducer rabbitMQProducer;
private final RabbitMQConsumer rabbitMQConsumer;
public Application(RabbitMQProducer rabbitMQProducer, RabbitMQConsumer rabbitMQConsumer) {
this.rabbitMQProducer = rabbitMQProducer;
this.rabbitMQConsumer = rabbitMQConsumer;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
rabbitMQProducer.send("Hello, RabbitMQ!");
}
}
After running the program, we can see output similar to the following on the console:
Received message: Hello, RabbitMQ!
This indicates that we have successfully sent a message to the queue and the consumer has successfully received the message.
RabbitMQ Advanced Features
In addition to basic functions, RabbitMQ also provides some advanced functions, such as:
message confirmation
When a producer sends a message, it does not know whether the message has been successfully processed. If the message is not successfully processed, the producer will keep trying to resend the message until it is successfully processed.
To solve this problem, RabbitMQ provides a message confirmation mechanism. When a producer sends a message, it can ask RabbitMQ to confirm whether the message has been successfully processed. If the message has been successfully processed, RabbitMQ will send an acknowledgment message to the producer.
@Component
public class RabbitMQProducer {
private final RabbitTemplate rabbitTemplate;
public RabbitMQProducer(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void send(String message) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("myExchange", "myRoutingKey", message, correlationData);
}
@Bean
public ConfirmCallback confirmCallback() {
return (correlationData, ack, cause) -> {
if (ack) {
System.out.println("Message with correlation id " + correlationData.getId() + " has been confirmed");
} else {
System.out.println("Message with correlation id " + correlationData.getId() + " has been rejected: " + cause);
}
};
}
}
In this example, we use the class in the producer CorrelationData
to track messages. We also created a ConfirmCallback
bean to handle message acknowledgments. When the message is successfully processed, confirmCallback
the method will be called and output a confirmation message. When the message is rejected, confirmCallback
the method will also be called and output a rejection message.
message persistence
By default, RabbitMQ does not persist messages to disk. If RabbitMQ doesn't deliver messages to consumers before it crashes, those messages will be lost.
To solve this problem, we can mark the message as persistent. This way, even if RabbitMQ crashes, messages are saved to disk and resent to consumers after RabbitMQ restarts.
@Component
public class RabbitMQProducer {
private final RabbitTemplate rabbitTemplate;
public RabbitMQProducer(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void send(String message) {
MessageProperties messageProperties = new MessageProperties();
messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
Message messageObject = new Message(message.getBytes(), messageProperties);
rabbitTemplate.send("myExchange", "myRoutingKey", messageObject);
}
}
In this example, we use the class in the producer MessageProperties
to set the persistence property of the message. We also use MessageDeliveryMode.PERSISTENT
the enumeration value to mark the message as persistent.
Message TTL
Message TTL (Time To Live) refers to the time when a message is stored in the queue. If the message is not consumed by the consumer within the specified time, it will be automatically removed from the queue.
@Component
public class RabbitMQProducer {
private final RabbitTemplate rabbitTemplate;
public RabbitMQProducer(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void send(String message) {
MessageProperties messageProperties = new MessageProperties();
messageProperties.setExpiration("5000"); // 5 seconds
Message messageObject = new Message(message.getBytes(), messageProperties);
rabbitTemplate.send("myExchange", "myRoutingKey", messageObject);
}
}
In this example, we use MessageProperties
the class in the producer to set the TTL property of the message. We messageProperties.setExpiration("5000")
set to 5000 milliseconds, which means messages are stored in the queue for a maximum of 5 seconds.
dead letter queue
A dead letter queue means that when a message is rejected or expires, it will be rerouted to another queue. This queue is called a dead letter queue.
@Configuration
public class RabbitMQConfig {
@Bean
public Queue myQueue() {
return QueueBuilder.durable("myQueue")
.withArgument("x-dead-letter-exchange", "myDeadLetterExchange")
.withArgument("x-dead-letter-routing-key", "myDeadLetterRoutingKey")
.build();
}
@Bean
public Queue myDeadLetterQueue() {
return QueueBuilder.durable("myDeadLetterQueue").build();
}
@Bean
public Exchange myExchange() {
return ExchangeBuilder.directExchange("myExchange").durable(true).build();
}
@Bean
public Exchange myDeadLetterExchange() {
return ExchangeBuilder.directExchange("myDeadLetterExchange").durable(true).build();
}
@Bean
public Binding binding() {
return BindingBuilder.bind(myQueue()).to(myExchange()).with("myRoutingKey").noargs();
}
@Bean
public Binding deadLetterBinding() {
return BindingBuilder.bind(myDeadLetterQueue()).to(myDeadLetterExchange()).with("myDeadLetterRoutingKey").noargs();
}
}
In this example, we create a myQueue
queue named and use withArgument
the method to specify its dead-letter exchange and routing key. We also created a myDeadLetterQueue
queue called and bound it to myDeadLetterExchange
an exchange called . Finally, we create the binding, which myQueue
binds the queue to myExchange
the exchange.
When a message myQueue
is rejected or expires in the , it will be re-routed to myDeadLetterExchange
the exchange, which will route it to myDeadLetterQueue
the queue.
Summarize
This article introduces the basic concepts of RabbitMQ and how to use RabbitMQ in Spring Boot. We also introduced some advanced features of RabbitMQ, including message confirmation, message persistence, message TTL and dead letter queue. By studying this article, you should have enough knowledge to start using RabbitMQ with Spring Boot.