在 RabbitMQ3.6.x 之前采用 死信队列 + TTL过期时间,来实现延迟队列。在 RabbitMQ3.6.x 之后,官方提供了延迟队列的插件,原理是在指定时间后,消息从交换机到达队列的时间。可以下载放置到 RabbitMQ 根目录下的 plugins 下。
下载插件
延迟队列插件下载,将插件放置在下载目录的 plugin 目录下,输入如下命令
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
示例
// 创建延迟交换机
@Bean
public TopicExchange lazyExchange() {
TopicExchange topicExchange = new TopicExchange(LAZY_EXCHANGE_NAME);
topicExchange.setDelayed(true);
return topicExchange;
}
/**
* 队列,用于取消订单,绑定延迟交换机
*
* @return
*/
@Bean
public Queue createOrderCancelQueue() {
return new Queue(ORDER_CANCEL_QUEUE_NAME, true, false, false);
}
/**
* 绑定延迟交换机与队列
*/
@Bean
public Binding lazyBinding() {
return BindingBuilder.bind(createOrderCancelQueue()).to(lazyExchange()).with(LAZY_KEY);
}
发送延迟消息
public void sendDelayMessage() {
rabbitTemplate.convertAndSend(RabbitMQOrderConfig.LAZY_EXCHANGE_NAME, RabbitMQOrderConfig.LAZY_KEY, mallOrder, queueMessage -> {
// 设置消息持久化
queueMessage.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
message.getMessageProperties().setHeader("x-delay", 1000 * 60);
// 订单延时时间为6秒,这种方式无效
// queueMessage.getMessageProperties().setDelay(1000 * 60 * 10);
return message;
});
}
监听延迟队列
@RabbitListener(queues = RabbitMQOrderConfig.ORDER_CANCEL_QUEUE_NAME)
@RabbitHandler
public void cancelOrder(Message message, Channel channel) throws Exception {
// 将消息转换为对象
Object object = JtObjectSerializableUtils.getObjectFromBytes(message.getBody());
MallOrder mallOrder = null;
if (object instanceof MallOrder) {
mallOrder = (MallOrder) object;
}
// 为了确保一致性,可设置手动应答
channel.basicQos((int) message.getMessageProperties().getDeliveryTag(), true);
}
工具类
public class JtObjectSerializableUtils {
/**
* 版权声明:本文为CSDN博主「east123321」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
* 原文链接:https://blog.csdn.net/east123321/article/details/78900791
* <p>
* 对象转字节码
*
* @param obj
* @return
* @throws Exception
*/
public static byte[] getBytesFromObject(Serializable obj) throws Exception {
if (obj == null) {
return null;
}
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(obj);
return bo.toByteArray();
}
/**
* 版权声明:本文为CSDN博主「east123321」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
* 原文链接:https://blog.csdn.net/east123321/article/details/78900791
*/
public static Object getObjectFromBytes(byte[] objBytes) throws Exception {
if (objBytes == null || objBytes.length == 0) {
return null;
}
ByteArrayInputStream bi = new ByteArrayInputStream(objBytes);
ObjectInputStream oi = new ObjectInputStream(bi);
return oi.readObject();
}
}