springboot整合rabbitMQ系列4 消费者Consumer 手动进行ack确认---消费者做到可靠性方案

本文详细介绍了RabbitMQ的三种消息确认模式,包括自动确认、手动确认和异常情况确认,并重点解析了手动确认的使用场景。通过一个具体的消费者代码示例展示了如何在业务处理成功后调用`channel.basicAck()`确认消息,以及在异常情况下使用`channel.basicNack()`重新发送消息。此外,还提供了消息序列化转换的配置代码,确保消息的正确处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ack指Acknowledge,确认。 表示消费端收到消息后的确认方式。
有三种确认方式:
自动确认:acknowledge="none"
手动确认:acknowledge="manual"
根据异常情况确认:acknowledge="auto",(这种方式使用麻烦,不作讲解)

其中自动确认是指,当消息一旦被Consumer接收到,则自动确认收到,并将相应 message 从 RabbitMQ 的消息缓存中移除。但是在实际业务处理中,很可能消息接收到,业务处理出现异常,那么该消息就会丢失。如果设置了手动确认方式,则需要在业务处理成功后,调用channel.basicAck(),手动签收,如果出现异常,则调用channel.basicNack()方法,让其自动重新发送消息

代码演示:用队列中的消息做除法运算,如果是整数,就会手动提交ack,如果是随便输入的文字,就会触发 basicNack


1 修改配置文件

server:
  port: 8021
spring:
  #给项目来个名字
  application:
    name: rabbitmq-test
  #配置rabbitMq 服务器
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: need
    password: 123456
    #虚拟host 可以不设置,使用server默认host
    virtual-host: /testhost

    #ack 确认方式
    listener:
      simple:
        acknowledge-mode: manual
      direct:
        acknowledge-mode: manual

相关的api解释

channel basicAck(long deliveryTag, boolean multiple);
deliveryTag:该消息的index
multiple:是否批量.true:将一次性ack所有小于deliveryTag的消息。

void basicNack(long deliveryTag, boolean multiple, boolean requeue);
deliveryTag:该消息的index
multiple:是否批量.true:将一次性拒绝所有小于deliveryTag的消息。
requeue:被拒绝的是否重新入队列

channel.basicReject(long deliveryTag, boolean requeue);
deliveryTag:该消息的index
requeue:被拒绝的是否重新入队列

channel.basicNack 与 channel.basicReject 的区别在于basicNack可以拒绝多条消息,而basicReject一次只能拒绝一条消息


2 消费者代码示例,有些是使用实现接口的方式 ,那是原生api的用法

        a:消息序列化转换代码

package org.example.service_b.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 此代码添加 在消费者的项目中
 */
@Configuration
public class RabbitmqGlobalConfig {

    /**
     * 当发送的消息为pojo时,为报转换异常
     * 解决方法:添加这个类进行序列化解析
     * 会自动识别
     * @param objectMapper json序列化实现类
     * @return mq 消息序列化工具
     */
    @Bean
    public MessageConverter jsonMessageConverter(ObjectMapper objectMapper) {
        return new Jackson2JsonMessageConverter(objectMapper);
    }

}

        b:接收消息代码 

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;

@Component
public class DirectReceiver_1  {

    
    @RabbitListener(queues = "TestDirectQueue")//监听的队列名称 TestDirectQueue
    /**
     * 注意:后3个参数,需要生产者发送消息时加上,否则为报错,注解里添加 required=false 或 删除参数
     */
    public void process(Message message,
                        Channel channel,
                        @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
                        @Header(AmqpHeaders.MESSAGE_ID) String messageId,
                        @Header(AmqpHeaders.CONSUMER_TAG) String consumerTag
                        ) throws IOException {

        //long deliveryTag = message.getMessageProperties().getDeliveryTag();
        //或 
        //@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag

        try {
            String msgbody = new String(message.getBody());
            //1.接收转换消息
            System.out.println("DirectReceiver消费者 1 收到消息  : " +msgbody+" 编号: "+deliveryTag);

            //2. 处理业务逻辑
            System.out.println("处理业务逻辑...");
            //模拟出现错误
            System.out.println(500/Double.valueOf(msgbody));
            //3. 手动签收
            channel.basicAck(deliveryTag,true);
        } catch (Exception e) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException interruptedException) {
                interruptedException.printStackTrace();
            }
            //e.printStackTrace();

            //4.拒绝签收
            /*
            第三个参数:requeue:重回队列。如果设置为true,则消息重新回到queue,broker会重新发送该消息给消费端
             */
            channel.basicNack(deliveryTag,true,true);
            //channel.basicReject(deliveryTag,true);
        }
    }
}

3 随便输入的消息,如图,未确认ack

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值