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


250

被折叠的 条评论
为什么被折叠?



