rabbitmq springboot 之 应答
springboot集成rabbitmq后, 关于应答这块 , 还是要先了解下rabbitmq本身的应答 :
先来回顾一下关于rabbitmq关于应答方面的一些小知识 (具体也可参考博客 https://www.cnblogs.com/qiyongchu/p/15540589.html ):
1 自动应答 , 发后即忘, 只要rabbitmq投递了消息给消费者,就认为投递成功,不管消费者是否真的收到了 , 这样可能会丢消息
2 手动应答:
channel.basicAck(long deliveryTag, boolean multiple) throws IOException;
代表消费者确认收到当前消息,语义上表示消费者成功处理了当前消息。
如果消费者没发送ACK,没有超时限制,rabbitmq也不会重复投递,只有消费者的 TCP 连接 或者 channel 关闭了,rabbitmq才会重复投递!
channel.basicNack(long deliveryTag, boolean multiple, boolean requeue) throws IOException
代表消费者拒绝一条或者多条消息。basicNack 算是 basicReject 的一个扩展,因为 basicReject 不能一次拒绝多
channel.basicReject(long deliveryTag, boolean requeue) throws IOException;
代表消费者拒绝这条消息,语义上表示消费者没有处理当前消息。
对于 basicNack 和 basicReject ,如果参数 boolean requeue 传入 false,消息还是会从队列里面删除。
那么rabbitmq与spring boot 结合后 , 跟上面有什么区别吗?
rabbitmq与spring boot 结合后,应答有三种情况 :
acknowledge-mode=none acknowledge-mode=auto acknowledge-mode=manual
1 NONE模式
默认推送的所有消息都已经消费成功,会不断地向消费端推送消息。消息丢失的风险 (其实我觉得,这个才是最像 "rabbitmq原生自动应答模式"的配置)
注意:NONE模式下 "spring.rabbitmq.listener.simple.default-requeue-rejected=true //重新入队" 这个配置不会生效 , 因为这种模式下 默认发完就算成功,不存在所谓"rejected"
2MANUAL模式 (手动模式)
package com.example.demo; import com.rabbitmq.client.Channel; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.Queue; import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer; import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener; import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar; import org.springframework.amqp.support.AmqpHeaders; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.context.annotation.Bean; import org.springframework.messaging.handler.annotation.Headers; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.Date; import java.util.Map; @Component @RabbitListener(queues = "hello") public class HelloReceiver { @RabbitHandler public void process(String hello,Channel channel, Message message) throws IOException { System.out.println("HelloReceiver收到 : " + hello +"收到时间"+new Date()); try { //告诉服务器收到这条消息 已经被我消费了 可以在队列删掉 这样以后就不会再发了 否则消息服务器以为这条消息没处理掉 后续还会在发 channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); System.out.println("receiver success"); } catch (IOException e) { e.printStackTrace(); //丢弃这条消息 或者 进入死信队列
channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);
//channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
System.out.println("receiver fail");
}
}
}
注意 : channel.basicReject(message.getMessageProperties().getDeliveryTag(),true); 的第二个参数是requeue , 这个参数跟 "spring.rabbitmq.listener.simple.default-requeue-rejected=true " 有重义 , 而却是方法的优先级高于配置的 . 有没有大佬能系统解释下这块的 .
3 AUTO模式 (看上去应该是自动应答, 其实跟rabbitmq本身的自动应答 不太一样,下面看分析 )
先说结论 : 该方式是通过抛出异常的类型,来做响应的处理
spring boot 配置
spring.rabbitmq.listener.simple.acknowledge-mode=auto spring.rabbitmq.listener.simple.default-requeue-rejected=true //重新入队 或者 spring.rabbitmq.listener.direct.acknowledge-mode=auto spring.rabbitmq.listener.direct.default-requeue-rejected=true //重新入队
这样配置后 是不是就是自动应答了呢? 跟rabbitmq自己的自动应答有什么区别吗?
上述配置后, 有以下效果
1)消息成功被消费,没有抛出异常,则自动确认。
2)当抛出 ImmediateAcknowledgeAmqpException
异常,则视为成功消费,确认该消息。
3)抛出 AmqpRejectAndDontRequeueException
异常的时候,则消息会被拒绝,且 requeue = false
(该异常会在重试超过限制后抛出)
4)其他的异常,则消息会被拒绝,且 requeue = true
根据以上几种效果看, 我觉得跟rabbitmq原生的自动应答还是有区别的,
rabbitmq原生的自动应答 ,只要消息发送给消费者(即便消费者内部有问题), 就会收到应答,删除消息, 并没有重新入队这个操作(我个人没发现原生rabbitmq的自动应答有).
但是spring boot集成rabbitmq之后,只要配置"default-requeue-rejected=true"
遇到异常后(除了AmqpRejectAndDontRequeueException
),就可以重新入队.
所以是不是springboot集成rabbitmq之后,在rabbitmq的基础上,重新设计了一些机制?
根据博客 https://blog.csdn.net/weixin_38380858/article/details/84963944 我们可以发现一些线索,
spring boot 跟 rabbitmq结合之后 , 应答机制方面,应该是是有些区别的