5.死信队列
Dead Letter Exchange(死信交换机),当消息成为Dead message后,可以被重新发送到另一个交换机,这个交换机就是DLX。
消息成为死信的三种情况:
1、队列的消息达到了限制时;
2、消费者拒绝接收消费消息,basicNack/basicReject,且不把消息重新放入目标队列中,requeue为false;
3、原队列存在消息过期设置,消息到达超时时间未被消费;
队列绑定死信交换机:
设置参数: x-dead-letter-exchange 和 x-dead-letter-routing-key
配置:
/**
* 声明正常的队列,设置x-dead-letter-exchange和x-dead-letter-routing-key
* 过期时间 100000
*/
@Bean("itemTopicQueue")
public Queue topicQueue(){
return QueueBuilder.durable(queue_name).withArgument("x-message-ttl",100000)
//x-dead-letter-exchange:死信交换机名称
.withArgument("x-dead-letter-exchange","exchange_dlx")
// x-dead-letter-routing-key:发送给死信交换机的routingkey
.withArgument("x-dead-letter-routing-key","dlx.e").build();
}
/**
* 声明死信队列
* @return
*/
@Bean("dlxQueue")
public Queue dlxQueue(){
return QueueBuilder.durable("queue_dlx").build();
}
/**
* 声明死信交换机
* @return
*/
@Bean("dlxTopicQueue")
public Exchange dlxExchange(){
return ExchangeBuilder.topicExchange("exchange_dlx").durable(true).build();
}
/**
* 绑定交换机
*/
@Bean
public Binding dlxQueueExchange(@Qualifier("dlxTopicQueue") Exchange exchange,
@Qualifier("dlxQueue") Queue queue){
//routingkey为绑定规则
// #通配多级
return BindingBuilder.bind(queue).to(exchange).with("dlx.#").noargs();
}
@Component
public class AckListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
//1.接收消息
System.out.println(new String(message.getBody()));
//2.业务处理逻辑
//TODO
//假如出现异常
int i=4/0;
//3.手动签收
channel.basicAck(deliveryTag,true);
} catch (Exception e) {
//4.拒绝签收 requeue=false 不重回队列,成为死信
channel.basicNack(deliveryTag,true,false);
//channel.basicReject(deliveryTag,true)
}
}
@Override
public void onMessage(Message message) {
ChannelAwareMessageListener.super.onMessage(message);
}
}
6.延迟队列
消息进入队列后不会立即消费,只有在指定时间后才会被消费。
比如提交订单后10分钟未支付自动取消订单,回滚库存
实现方法:定时器,延迟队列
rabbitmq中未提供延迟队列的功能。但是可以使用TTL+死信队列组合实现延迟队列的效果
步骤:
-
定义正常交换机(order_exchange)和队列(order_queue)
-
定义死信交换机(order_exchange_dlx)和队列(order_queue_dlx)
-
绑定,设置正常队列过期时间为30分钟
配置:
/**
* 声明交换机
* @return
*/
@Bean("orderTopicExchange")
public Exchange topicExchange(){
return ExchangeBuilder.topicExchange("order_exchange").durable(true).build();
}
/**
* 声明正常的队列,设置x-dead-letter-exchange和x-dead-letter-routing-key
* 过期时间 10000 --10秒钟
*/
@Bean("oderTopicQueue")
public Queue topicQueue(){
return QueueBuilder.durable("order_queue").withArgument("x-message-ttl",10000)
//x-dead-letter-exchange:死信交换机名称
.withArgument("x-dead-letter-exchange","order_exchange_dlx")
// x-dead-letter-routing-key:发送给死信交换机的routingkey
.withArgument("x-dead-letter-routing-key","dlx.order.quxiao").build();
}
/**
* 声明死信队列
* @return
*/
@Bean("dlxQueue")
public Queue dlxQueue(){
return QueueBuilder.durable("queue_dlx").build();
}
/**
* 声明死信交换机
* @return
*/
@Bean("dlxTopicQueue")
public Exchange dlxExchange(){
return ExchangeBuilder.topicExchange("order_exchange_dlx").durable(true).build();
}
/**
* 绑定交换机
*/
@Bean
public Binding dlxQueueExchange(@Qualifier("dlxTopicQueue") Exchange exchange,
@Qualifier("dlxQueue") Queue queue){
//routingkey为绑定规则
// #通配多级
return BindingBuilder.bind(queue).to(exchange).with("dlx.oder.#").noargs();
}
/**
* 绑定交换机
*/
@Bean
public Binding itemQueueExchange(@Qualifier("orderTopicExchange") Exchange exchange,
@Qualifier("oderTopicQueue") Queue queue){
//routingkey为绑定规则
// #通配多级
return BindingBuilder.bind(queue).to(exchange).with("order.#").noargs();
}
发送端
/**
* 测试延迟队列-订单过期
*/
@Test
public void testOder() throws InterruptedException {
//发送消息
rabbitTemplate.convertAndSend("order_exchange","order.demo","消息...");
//10秒倒计时
for(int i=10;i>0;i--){
System.out.println(i+"秒后过期...");
Thread.sleep(1000);
}
System.out.println("已过期...");
}