一、什么是死信队列
rabbitmq.com/dlx.html
死信交换机绑定的队列就叫死信队列。什么叫死信交换机?接收死信消息的交换机叫做死信交换机。什么叫做死信消息?
- 消息被拒绝,又没有重新入队的消息(basic.nack | basic.reject & requeue = false)
- 消息过期
- 队列达到最大长度后来的消息
其实,死信队列就是一个专门用来处理死信消息的普通队列,而死信交换机也只是一个用来接收死信消息的普通交换机。它们都没有特殊的地方。
二、应用场景
死信队列主要用来实现延时任务。
- 订单超时取消支付
- 红包失效
- 7天自动确认收货
三、实现原理
业务消息放到一个普通队列A中,队列A不要有消费者,设置队列A的过期时间及绑定的死信队列,当消息过期后,会被投送到死信队列B中,监听队列B的消息进行处理。
四、实战
/**
* 订单交换机
* @return
*/
@Bean
public TopicExchange orderExchange(){
return new TopicExchange(MQConstant.ORDER_EXCHANGE);
}
/**
* 死信队列【一个普通队列】
*/
@Bean
public Queue dlQueue(){
return new Queue(MQConstant.ORDER_DL_QUEUE, true, false, false);
}
/**
* 延迟队列【不被监听】
* @return
*/
@Bean
public Queue orderQueue(){
// 10s 消息未消费 -> 进入死信队列
Map<String, Object> args = new HashMap<>();
args.put(MQConstant.DLE, MQConstant.ORDER_EXCHANGE);
args.put(MQConstant.DLK, MQConstant.CANCEL_DL_ROUTE_KEY);
args.put(MQConstant.TTL, 10000);
return new Queue(MQConstant.ORDER_CREATE_QUEUE, true, false, false, args);
}
/**
* 死信队列绑定到交换机
* @return
*/
@Bean
public Binding bindDl(){
return BindingBuilder
.bind(dlQueue())
.to(orderExchange())
.with(MQConstant.CANCEL_DL_ROUTE_KEY)
;
}
/**
* 延迟队列绑定到交换机
*/
@Bean
public Binding bindDelayQueue(){
return BindingBuilder
.bind(orderQueue())
.to(orderExchange())
.with(MQConstant.ORDER_ROUTE_KEY);
}
消费者,监听死信队列
@Component
public class OrderCancelReceiver {
@RabbitListener(queues = {MQConstant.ORDER_DL_QUEUE})
public void cancelOrder(Message message, Channel channel) throws IOException {
System.out.println(new String (message.getBody()));
System.out.println(new Date());
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
}
}