rabbitmq学习之路(五)

上一篇讲了消息发送确认,这一次来讲一讲 消息消费确认模式

消息发送确认,确认的是消息发送到交换机和队列的确认,消息消费确认则确认的是消息是否被消费者正常消费掉!

消息的确认模式有三种

  • AcknowledgeMode.NONE:自动确认
  • AcknowledgeMode.AUTO:根据情况确认
  • AcknowledgeMode.MANUAL:手动确认

手动确认是程序员控制度最高的一种模式,消息的自动确认是在消息发送给消费者后就确认了,并删除消息,如果消费者在执行过程中出错,依然会造成消息的丢失。第二种模式则会根据消费者的执行情况,抛出的异常来决定是确认还是拒绝等。

贴一下练习的代码

因为我是把生产者和消费者分开在两个项目中的,然后我发现

spring.rabbitmq.listener.simple.acknowledge-mode=manual这个配置需要两边都配置上,否则就不会开启手动确认模式!
@Component
public class Publisher {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void send(){
        String message = "mck learn rabbitmq";
        User user = new User();
        user.setName("mck");
        user.setAge(25);
        user.setSex("男");

        MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setHeader("error","mck");
                return message;
            }
        };

        rabbitTemplate.convertAndSend("hello",user,messagePostProcessor);

    }

}
@Component

public class Receiver {

    @RabbitHandler
    @RabbitListener(queues = "hello")
    public void process(@Payload User user, Channel channel, @Headers Map<String,Object> map){
        System.out.println(user.getName());
        if (map.get("errorrr")!= null){
            System.out.println("错误的消息");
            try {
                channel.basicNack((Long)map.get(AmqpHeaders.DELIVERY_TAG),false,true);      //否认消息
                return;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            channel.basicAck((Long)map.get(AmqpHeaders.DELIVERY_TAG),false);            //确认消息
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

经过多次的测试发现了,如果开启手动确认模式之后,消息没有进行确认的话,消费者会继续消费下一条消息,就像我们前面的文章讲的,broker中,分为两部分,一部分是待发送的消息,一部分是已发送,但是没有收到确认的消息。

    我们可以在控制台看到,这部分unacked 就是已发送,但是没有收到确认的消息。这时候如果你将消费者强制关闭,也就是使他断开连接,那么这条消息又会重新进入ready队列去,当你将消费者重启之后,就会再次收到这条消息!!!!

    我们在消费者代码中还能看到手动的nack消息,nack消息也就意味着告诉broker,这条消息我没有消费好,请重新放入队列,重来一遍,然后就是重新进入ready,再度去被消费者消费。除此之外还可以拒绝消息,

channel.basicReject((Long)map.get(AmqpHeaders.DELIVERY_TAG),false);      这样处理的消息就会直接丢失掉!!!

原文地址:https://www.cnblogs.com/changeCode/p/11307308.html

时间: 2024-10-24 22:31:04

rabbitmq学习之路(五)的相关文章

rabbitmq学习之路(三)

今天继续学习rabbitmq 了解一下AMQP的一些基本概念 交换机: Direct exchange(直连交换机) Fanout exchange(扇型交换机) Topic exchange(主题交换机) Headers exchange(头交换机) 交换机有两个状态 持久和暂存,区别就是持久话的交换机在消息代理也就是broker重启后依旧存在 队列: 队列需要被声明之后才能使用,如果声明时,该队列不存在,就会新建,如果已经存在,且属性无变化,则没有关系,不影响,若属性有变化,则报错 队列和交

react.js学习之路五

最近没时间写博客,但是我一直在学习react,我发现react是一个巨大的坑,而且永远填不完的坑 关于字符串的拼接: 在react中,字符串的拼接不允许出现双引号"" ,只能使用单引号' ',例如这样就是可以的,这经常用在使用变量,变换路径的情况下. <img src={'img/sort_goods_0'+(index+1)+'x.png'} />

python学习之路 五:函数式编程

本节重点 掌握函数的作用.语法 掌握作用域.全局变量与局部变量知识 一.函数编程基础知识 1.基本定义 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需要调用函数名即可. 2.特性 ?(1)减少重复代码 ?(2)使程序变得可扩展 ?(3)使程序变得易维护 3.语法定义 def sayhi(): # 函数名 print("Hello,i'm nobody!") 二.函数参数 1.形参变量 只有在被调用时才分配内存单元,在调用结束时,即可释放所分配的内存单元.

Swift学习之路五(构造过程Initialization)

写在前面 喜欢我们的内容,可以订阅我们的官方微信公众账号:乐Coding.我们的iOS高级开发QQ群:386572485. 构造过程(Initialization),Swift中的构造器和Objective-C中的构造函数还是有很大不同的.即使Swift中类的构造器和值类型 (枚举和结构体)的构造器也有所不同. 下面我们慢慢看到底有那些不同. 1. 构造器,构造过程包括为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务: 与 Objective-C 中的构造器不同,Swift 的构造器

Java学习之路(五)

1:补充: 使用super也可以调用父类的成员函数  格式 :  super.函数名(); 2:抽象类与抽象函数 抽象函数的定义: 只有函数的定义,没有函数体的函数被称为抽象函数 抽象类的定义: 使用abstract定义的类被称为抽象类 注意: 1:抽象类不能被实例化 2:如果一个类当中包含有抽象函数,那么这个类必须被声明为抽象类 3:如果一个类中没有抽象函数,那么这个类也可以被声明为抽象类 抽象类不能生成对象  却可以有构造函数 如果一个不是抽象的子类继承了抽象类那就必须实现抽象(父)类中的所

oracle学习之路(五)-----oracle数据类型的一般操作

1. 一些常见的运算符 运算符 意义 = 等于 <> , != , ~= , ^= 不等于 < 小于 > 大于 <= 小于或等于 >= 大于或等于 + 加号 - 减号 * 乘号 / 除号 := 赋值号 => 关系号 .. 范围运算 || 字符连接符 IS NULL 是空值 BETWEEN AND 介于两者之间 IN 在一列值中间 AND 逻辑与 OR 逻辑或 NOT 取返,如IS NOT NULL, NOT IN 2.变量赋值 在PL/SQL编程中,变量赋值是一个

android开发学习之路——连连看之游戏逻辑(五)

GameService组件则是整个游戏逻辑实现的核心,而且GameService是一个可以复用的业务逻辑类. (一)定义GameService组件接口 根据前面程序对GameService组件的依赖,程序需要GameService组件包含如下方法.   ·start():初始化游戏状态,开始游戏的方法.     ·Piece[][] getPieces():返回表示游戏状态的Piece[][]数组.     ·boolean hasPieces():判断Pieces[][]数组中是否还剩Piec

OpenGL学习之路(五)

1 引子 不知不觉我们已经进入到读书笔记(五)了,我们先对前四次读书笔记做一个总结.前四次读书笔记主要是学习了如何使用OpenGL来绘制几何图形(包括二维几何体和三维几何体),并学习了平移.旋转.缩放坐标变换矩阵的理论推导和实践应用. 这一次读书笔记,我们一起来学习OpenGL中常用的坐标系以及坐标变换.在OpenGL中有几个坐标系,初学者常常被它们搞得晕头转向:为什么需要这些坐标系?各个坐标系有什么作用?……本文就来学习一下这些OpenGL中常用坐标系. 之后来看看投影矩阵的推导,投影变换矩阵

RabbitMQ学习笔记五:RabbitMQ之优先级消息队列

RabbitMQ优先级队列注意点: 1.只有当消费者不足,不能及时进行消费的情况下,优先级队列才会生效 2.RabbitMQ3.5以后才支持优先级队列 代码在博客:RabbitMQ学习笔记三:Java实现RabbitMQ之与Spring集成 最后面有下载地址,只是做了少许改变,改变的代码如下: 消费者 spring-config.xml(还需要增加一个QueueListener监听器,代码就不复制到这里了,可以参考项目中的其他监听器) <!-- =========================