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

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
    /**
     * 注意:后4个参数,需要生产者发送消息时加上,否则为报错,注解里添加 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,
                        CorrelationData correlationData) 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

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot整合RabbitMQ进行手动签收的方法如下所示: 1. 首先,你可以创建一个消费者类,并在该类上添加`@RabbitListener`注解,指定监听的队列。例如,可以创建一个名为`FanoutReceiverB`的消费者类,使用`@RabbitListener(queues = "fanout.B")`指定监听队列为"fanout.B"。 2. 在消费者类中,可以使用`@RabbitHandler`注解标注一个处理消息的方法,该方法接受一个消息参数。例如,在`FanoutReceiverB`类中,可以定义一个名为`process`的方法,参数为`Map testMessage`,用来处理接收到的消息。 3. 在处理方法中,你可以根据业务逻辑进行相应的处理,并手动确认消息的签收。你可以使用`channel.basicAck`方法来手动确认消息的签收。例如,可以在`process`方法中调用`channel.basicAck`方法来手动确认消息的签收。 4. 最后,你需要在pom.xml文件中添加RabbitMQ的相关依赖。可以添加`spring-boot-starter-amqp`和`spring-boot-starter`依赖。例如,在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> ``` 通过以上步骤,你就可以在SpringBoot中实现手动签收RabbitMQ消息了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [RabbitMQSpringBoot中实现手动签收重试三次进入死信队列](https://blog.csdn.net/shang_0122/article/details/120617954)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Springboot 整合RabbitMq ,原来这么简单](https://blog.csdn.net/biglow/article/details/119633573)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值