How to Implement RabbitMQ Delayed Messages with the Delayed Plugin in Spring Boot
This guide walks through installing the RabbitMQ delayed‑message‑exchange plugin, configuring it in a Spring Boot application, and building Java components to send and receive delayed order‑cancellation messages, comparing the plugin approach with dead‑letter queues and providing complete code snippets and deployment steps.
RabbitMQ implements delayed messages in two ways: using a dead‑letter queue or using the delayed‑message‑exchange plugin . The dead‑letter method has been covered elsewhere; this article focuses on the simpler plugin approach.
Preparation
To follow this tutorial you should already be familiar with RabbitMQ. If not, see the article "RabbitMQ Practical Tips".
Plugin Installation
First download and install the RabbitMQ delayed‑message‑exchange plugin.
Download the plugin from the official RabbitMQ site: https://www.rabbitmq.com/community-plugins.html
Or search for
rabbitmq_delayed_message_exchangeand download the version that matches your RabbitMQ installation.
Copy the plugin file into the
pluginsdirectory of your RabbitMQ installation.
In the
sbindirectory, enable the plugin with the command:
<code>rabbitmq-plugins enable rabbitmq_delayed_message_exchange</code>After successful enablement, restart the RabbitMQ service.
Implement Delayed Messages
We will implement delayed messages in a Spring Boot project using an order‑cancellation scenario: if a user does not pay within 60 minutes, the order is automatically cancelled.
Add the AMQP starter dependency to
pom.xml:
<code><!--消息队列相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</code>Configure RabbitMQ in
application.yml:
<code>spring:
rabbitmq:
host: localhost # rabbitmq host
port: 5672 # rabbitmq port
virtual-host: /mall # virtual host
username: mall # username
password: mall # password
publisher-confirms: true # enable confirms for async messages
</code>Create a Java configuration class to define the custom exchange, queue, and binding:
<code>/**
* Message queue configuration
*/
@Configuration
public class RabbitMqConfig {
/**
* Custom exchange for delayed messages
*/
@Bean
CustomExchange orderPluginDirect() {
Map<String, Object> args = new HashMap<>();
args.put("x-delayed-type", "direct");
return new CustomExchange(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getExchange(), "x-delayed-message", true, false, args);
}
/**
* Queue for delayed order cancellation
*/
@Bean
public Queue orderPluginQueue() {
return new Queue(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getName());
}
/**
* Bind the queue to the custom exchange
*/
@Bean
public Binding orderPluginBinding(CustomExchange orderPluginDirect, Queue orderPluginQueue) {
return BindingBuilder.bind(orderPluginQueue)
.to(orderPluginDirect)
.with(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getRouteKey())
.noargs();
}
}
</code>Sender component that publishes a message with the
x-delayheader:
<code>/**
* Sender for order‑cancellation messages
*/
@Component
public class CancelOrderSender {
private static final Logger LOGGER = LoggerFactory.getLogger(CancelOrderSender.class);
@Autowired
private AmqpTemplate amqpTemplate;
public void sendMessage(Long orderId, final long delayTimes) {
amqpTemplate.convertAndSend(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getExchange(),
QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getRouteKey(),
orderId,
message -> {
message.getMessageProperties().setHeader("x-delay", delayTimes);
return message;
});
LOGGER.info("send delay message orderId:{}", orderId);
}
}
</code>Receiver component that processes delayed messages:
<code>/**
* Receiver for order‑cancellation messages
*/
@Component
@RabbitListener(queues = "mall.order.cancel.plugin")
public class CancelOrderReceiver {
private static final Logger LOGGER = LoggerFactory.getLogger(CancelOrderReceiver.class);
@Autowired
private OmsPortalOrderService portalOrderService;
@RabbitHandler
public void handle(Long orderId) {
LOGGER.info("receive delay message orderId:{}", orderId);
portalOrderService.cancelOrder(orderId);
}
}
</code>Modify the order service to send a delayed cancellation message after an order is placed:
<code>/**
* Front‑end order service implementation
*/
@Service
public class OmsPortalOrderServiceImpl implements OmsPortalOrderService {
private static final Logger LOGGER = LoggerFactory.getLogger(OmsPortalOrderServiceImpl.class);
@Autowired
private CancelOrderSender cancelOrderSender;
@Override
public CommonResult generateOrder(OrderParam orderParam) {
// ... order creation logic ...
LOGGER.info("process generateOrder");
// Send a 30‑second delayed cancellation message (for demo)
sendDelayMessageCancelOrder(11L);
return CommonResult.success(null, "Order placed successfully");
}
@Override
public void cancelOrder(Long orderId) {
// ... order cancellation logic ...
LOGGER.info("process cancelOrder orderId:{}", orderId);
}
private void sendDelayMessageCancelOrder(Long orderId) {
long delayTimes = 30 * 1000; // 30 seconds for testing
cancelOrderSender.sendMessage(orderId, delayTimes);
}
}
</code>Start the application and invoke the order‑creation API via Swagger.
Check the console logs; the receive log appears after the configured 30‑second delay.
<code>2020-06-08 13:46:01.474 INFO 1644 --- [nio-8080-exec-1] c.m.m.t.s.i.OmsPortalOrderServiceImpl : process generateOrder
2020-06-08 13:46:01.482 INFO 1644 --- [nio-8080-exec-1] c.m.m.tiny.component.CancelOrderSender : send delay message orderId:11
2020-06-08 13:46:31.517 INFO 1644 --- [cTaskExecutor-4] c.m.m.t.component.CancelOrderReceiver : receive delay message orderId:11
2020-06-08 13:46:31.520 INFO 1644 --- [cTaskExecutor-4] c.m.m.t.s.i.OmsPortalOrderServiceImpl : process cancelOrder orderId:11
</code>Comparison of Two Implementations
We previously used the dead‑letter‑queue method; here we compare both approaches.
Dead Letter Queue
A dead‑letter queue forwards messages that exceed a TTL to another queue, enabling delayed processing.
Delayed Plugin
Installing the plugin creates a custom exchange that can delay message delivery directly.
Conclusion
The dead‑letter method requires two exchanges and two queues, whereas the delayed‑plugin method needs only one exchange and one queue, making the plugin approach simpler to use.
Project Source Code
https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-delay
Recommended Reading
RabbitMQ Practical Tips
Why Program to Interfaces?
SQL Optimization Interview Tips
IDEA‑like Database Management Tool Review
15 Developer Tools Used by Alibaba Engineers
Open‑Source Git Service Project with 34K Stars
Tips for Optimizing a Slow PC After IDEA Update
Automation Deployment Tricks I Use Frequently
Spring Cloud Hands‑On Project Recommendation
My Open‑Source Projects: From 0 to 20K Stars
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.