rabbitMQ消息队列中发布确认中的确认以及回退回调的实现

本文详细介绍了在rabbitMQ中如何实现发布确认回调和消息不可路由时的回退回调,以防止消息丢失。重点在于理解如何在发布确认回调实现类中设置ConfirmCallBack,确保即使遇到服务器宕机或队列问题也能正常执行确认。此外,还讨论了消息不可路由的两种解决方案:一是通过回退回调,当路由key未找到时将消息退回;二是设置备份交换机,当消息无法路由时,备份交换机会接管处理。配置文件的相应设置也是关键部分。

在发布确认回调实现类中

package com.it.springbootrabbitmq.callback;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Slf4j
@Component
//发布确认回调实现类
public class MyCallBack  implements RabbitTemplate.ConfirmCallback {

    @Autowired
    private  RabbitTemplate rabbitTemplate;
    //由于confirm回调函数是在rabbitTemplate类中进行调用的, 调用方法为handleConfirm .只有属性ConfirmCallBack
    //	if (this.confirmCallback != null) {
    //		this.confirmCallback
    //		.confirm(pendingConfirm.getCorrelationData(), ack, pendingConfirm.getCause()); // NOSON
    //不为null  才会被调用 因此, 需要首先在类注入后, 进行初始化,为回调实现类进行赋值,进而每次发出消息都会激发回调函数
    //且 PostConstruct  注解是专门数据初始化的注解, 只有其他组件注入后,初始化方法才会执行,
    @PostConstruct
    public void  init(){
        rabbitTemplate.setConfirmCallback(this);
    }

    //交换机确认回调方法
    /*
    * correlationData   保存回调消息的ID及相关信息
    * ack   表示交换机是否收到消息
    * cause   失败的原因, 成功为null
    * */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
      String  id= correlationData!=null?correlationData.getId() : "";
      if (ack){
          log.info("交换机已经收到了ID为:{}的消息", id);
      }else {
          log.info("交换机还未收到ID为:{}的消息,由于原因:{}", id,cause );
      }

    }
}

难理解的地方:
在这里插入图片描述

这里首先需要注入rabbitTemplate操作工具类,这是依赖为我们提供好的, 而我们虽然实现了实现类, 但由于实现的是rabbitTemplate类的内部接口,在其类中声明了ConfirmCallBack属性, 我查看源码注意到一个方法
在这里插入图片描述
这个方法 很清楚的key看到 ,只有在confirCallback确认回调不为null 时才会执行其中的回调实现类调用确认confirm方法的逻辑, 因此, 我们在数据初始化的时候, 必须在给rabbittemplate中注入confirmCallback值, 进行数据的初始化, 这样在消费者发送消息后,不管中间出现了什么问题:rabbbit服务器宕机,队列挂掉,等等, 都是正常执行确认回调函数, 确认ack位true 未确认为false , 这样就解决了 rabbbit服务器宕机,队列挂掉等原因造成的消息丢失的故障问题

消息不可路由的解决方式一: 回退回调

  //可以在当消息传递过程中不可达目的地时将消息返回给生产者
    //只有不可达目的地的时候  才进行回退

    @Override
    public void returnedMessage(ReturnedMessage returned) {
        log.info("消息{},被交换机:{}退回,原因是:{},路由key是:{}",
                new String(returned.getMessage().getBody()), returned.getExchange(), returned.getReplyText(), returned.getRoutingKey());

    }

因为只设置发布交换机确认回调的话,只能解决交换机宕机的问题, 而在 队列,未收到消息, 也就是路由key no found 的情况下, 交换机还会>
正常确认, 因为其已收到消息, 但我们需要知道队列是否 收到, 如果没有收到的话, 能够将消息给发送者退回, 进行其他处理
因此, 我们需要实现回退, 同样实现回退接口, 然后实现方法
同样的, 回退回调实现类也需要注入到rabbitTemplate类中, 才会进行调用

完整发布确认代码如下

package com.it.springbootrabbitmq.callback;

import com.rabbitmq.client.ReturnCallback;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Slf4j
@Component
//发布确认回调实现类
public class MyCallBack  implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //由于confirm回调函数是在rabbitTemplate类中进行调用的, 调用方法为handleConfirm .只有属性ConfirmCallBack
    //	if (this.confirmCallback != null) {
    //		this.confirmCallback
    //		.confirm(pendingConfirm.getCorrelationData(), ack, pendingConfirm.getCause()); // NOSON
    //不为null  才会被调用 因此, 需要首先在类注入后, 进行初始化,为回调实现类进行赋值,进而每次发出消息都会激发回调函数
    //且 PostConstruct  注解是专门数据初始化的注解, 只有其他组件注入后,初始化方法才会执行,
    @PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnsCallback(this);
    }


    //交换机确认回调方法
    /*
     * correlationData   保存回调消息的ID及相关信息
     * ack   表示交换机是否收到消息
     * cause   失败的原因, 成功为null
     * */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String id = correlationData != null ? correlationData.getId() : "";
        if (ack) {
            log.info("交换机已经收到了ID为:{}的消息", id);
        } else {
            log.info("交换机还未收到ID为:{}的消息,由于原因:{}", id, cause);
        }

    }
    //可以在当消息传递过程中不可达目的地时将消息返回给生产者
    //只有不可达目的地的时候  才进行回退

    @Override
    public void returnedMessage(ReturnedMessage returned) {
        log.info("消息{},被交换机:{}退回,原因是:{},路由key是:{}",
                new String(returned.getMessage().getBody()), returned.getExchange(), returned.getReplyText(), returned.getRoutingKey());

    }
}

配置文件需要进行如下配置:

#开启交换机发布确认模式,交换机收到或者未收到消息, 都会调用回调实现类的回调确认方法
spring.rabbitmq.publisher-confirm-type=correlated
#开启回退消息 , 当交换机无法将消息路由出去, 便会将消息回退给生产者
spring.rabbitmq.publisher-returns=true

消息不可路由的解决方式二:设置备份交换机

通过设置备份交换机进行解决消息不可路由 在确认交换机中, 设置备份交换机参数, 这样当消息不可路由的时候,确认交换机便会将
消息传递给备份交换机进行处理 而且 由于回退实现类也就是mandatory参数与备份交换机一起使用的时候, 如果两者同时开始, 备份交换机优先级要搞

 //声明确认交换机
    @Bean
    public DirectExchange  confirmExchange(){

        return  ExchangeBuilder.directExchange(CONFIRM_EXCHANGE_NAME)
       //这里是alternate 是将确认交换机与备份交换机建立关系, 一旦发现不可路由消息,便会将消息传递给备份交换机处理
                .alternate(BACKUP_EXCHANGE_NAME).build();
    }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值