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结合之后 , 应答机制方面,应该是是有些区别的

 


        

 

 

posted @ 2021-11-29 16:13  代达罗斯之殇  阅读(665)  评论(0编辑  收藏  举报