一、确认流程
二、Spring Boot整合RabbitMQ消息确认机制
1、生产者确认
application.yml配置文件配置
spring:
rabbitmq:
host: 127.0.0.1
port: 7006
username: admin
password: admin
# 是否触发回调方法
# NONE值是禁用发布确认模式,是默认值
# CORRELATED值是发布消息成功到交换器后会触发回调方法,如1示例
# SIMPLE值经测试有两种效果,其一效果和CORRELATED值一样会触发回调方法,其二在发布消息成功后使用rabbitTemplate调用waitForConfirms或waitForConfirmsOrDie方法等待broker节点返回发送结果,根据返回结果来判定下一步的逻辑,要注意的点是waitForConfirmsOrDie方法如果返回false则会关闭channel,则接下来无法发送消息到broker;
publisher-confirm-type: correlated
publisher-returns: true
listener:
simple:
# 开启手动确定
acknowledge-mode: manual
设置消息发送到交换机时的回调函数 + 消息从交换机发送到队列时失败的回调函数
package com.cyun.demo.rabbitmq.provider.config;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* 确认机制(消息发送到服务回调)
*
* @author He PanFu
* @date 2022-04-16 18:29:03
*/
@Component
public class RabbitmqSendCallback implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {
@Resource
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void run() {
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnCallback(this);
}
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
if (b) {
System.out.println("消息发送成功");
} else {
System.out.println("消息发送失败,进行容错处理");
}
System.out.println("消息发送到交换机时的回调函数, ack:" + b + " 消息体:" + s);
}
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
System.out.println("消息从交换机发送到队列时失败的回调函数, 调用失败!!!");
}
}
模拟消息发送到交换机失败(发布/订阅模式)
- 修改发送消息的交换机为错误交换机
- 结果
模拟消息从交换机发送到队列时失败(简单模式)
- 修改发送消息的队列为错误交换机
- 结果
2、消费者确认
代码
package com.cyun.demo.rabbitmq.consumer;
import com.rabbitmq.client.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Map;
/**
* 简单模式:队列监听
*
* @author He PanFu
* @date 2022-04-14 16:24:20
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class RabbitmqSimpleListener {
int i = 0;
@RabbitListener(queues = "simple_queue")
public void messageListener(Map messageMap, Channel channel, Message message) throws InterruptedException, IOException {
try {
// 模拟业务出错
if (i++ % 3 == 0) {
int i = 0 / 0;
}
// TimeUnit.SECONDS.sleep(2);
log.info("消息处理完成,消息内容:{}", messageMap);
// 进行手动确定
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
} catch (Exception e) {
log.info("消息处理失败,消息内容:{}", messageMap);
// 消息被否定。multiple:是否批量处理.true:将一次性ack所有小于deliveryTag的消息,requeue:为true时,重新入队
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
e.printStackTrace();
}
}
}