RabbitMQ消费者确认消息入门演示
满足死信交换机有三种情况分别是 :
消费者使用basic.reject或 basic.nack声明消费失败,并且消息的requeue参数设置为false
消息是一个过期消息,超时无人消费
要投递的队列消息满了,无法投递
在上篇文章讲到的RepublishMessageRecoverer因为消费者内部出现异常, 导致重试次数耗尽, 为了消息不会丢弃, 我们直接将消费者消息发送到(error.direct)失败交换机中
如下图所示这次我们所讲的死信交换机种, 我们发现明显的差别, 在死信中, 异常消息没有到达消费者, 而是直接到达了交换机(dl.direct)
一个队列中的消息如果超时未消费,则会变为死信,超时分为两种情况:
消息所在的队列设置了超时时间
消息本身设置了超时时间
下面我们用代码演示如何接收超时死信的死信交换机的消息
//-----------------死信队列---------------------------
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "dl.queue", durable = "true"),
exchange = @Exchange(name = "dl.direct"),
key = "dl"
))
public void listenDlQueue(String msg){
log.info("消费者接收到了dl.queue的延迟消息:{}", msg);
}
//-----------------死信队列---------------------------
值得注意的是, 在声明队列时, 我们要指定对应的死信交换机才可以, 而且因为设置了10秒的超时时间, 也就是在十秒之后会收到死信队列的监听消息
@Bean
public DirectExchange ttlDirectExchange(){
return new DirectExchange("ttl.direct");
}
@Bean
public Queue ttlQueue(){
return QueueBuilder
// 指定队列名称,并持久化
.durable("ttl.queue")
// 设置队列的超时时间,10秒
.ttl(10000)
// 指定死信交换机
.deadLetterExchange("dl.direct")
//指定死信的RoutingKey
.deadLetterRoutingKey("dl")
.build();
}
@Bean
public Binding ttlBinding(){
return BindingBuilder.bind(ttlQueue()).to(ttlDirectExchange()).with("ttl");
}
@Test
public void testTTLMessage() {
// 1.准备消息
Message message = MessageBuilder
.withBody("hello, ttl messsage".getBytes(StandardCharsets.UTF_8))
.setDeliveryMode(MessageDeliveryMode.PERSISTENT)
.build();
// 2.发送消息
rabbitTemplate.convertAndSend("ttl.direct", "ttl", message);
// 3.记录日志
log.info("消息已经成功发送!");
}
我们发消息的时间在28秒的时候
之前我们设置了10秒的超时时间, 所以在第38秒的时候, 我们的死信队列成功收到了消息
之所以消息会进入死信队列是因为没有消费者去消费这条消息, 如果正常想正常消费可以加入如下代码
/**
* 如果不想走死信队列就走如下代码, 因为消费者已经消费后就不会进入死信队列
* @param msg
*/
@RabbitListener(queues = "ttl.queue")
public void ttlQueue(String msg){
log.info("接受ttl的消息, 为了不让死信队列去监听而定义的:{}", msg);
}
链接:https://pan.baidu.com/s/1il41ywFnYM4_q3MU9GN_MQ
提取码:heng