版本说明
- SpringBoot 3.0.2,另需引入spring-boot-starter-amqp
- RabbitMQ 3.12
资料参考
参考自黑马教程:MQ高级-04.发送者可靠性-发送者确认的代码实现_哔哩哔哩_bilibili
注意事项
我这边可能是版本比较新,有的api找不到,所以与上述【资料参考】中的步骤2、3实现有所不同。
开启确认机制
spring.rabbitmq.publisher-confirm-type=correlated
spring.rabbitmq.publisher-returns=true
ReturnsCallback配置
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
/**
* 发送者确认机制之publisher-returns机制returnsCallback,
* 一个微服务项目配置一个。
*
* @author liaorj
* @date 2024/4/26
*/
@Slf4j
@Component
public class ReturnsCallbackConfig implements RabbitTemplate.ReturnsCallback {
@Resource
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void init() {
rabbitTemplate.setReturnsCallback(this);
}
@Override
public void returnedMessage(ReturnedMessage returnedMessage) {
try {
log.info("returnsCallback回调信息:{}", new ObjectMapper().writeValueAsString(returnedMessage));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}
ConfirmCallback配置
@RequestMapping("/testConfirm")
public Boolean testConfirm() {
CorrelationData cd = new CorrelationData();
String msg = "你好3,本次是为了测试发送者确认机制!";
rabbitTemplate.convertAndSend("test.direct", "test1", msg, cd);
//confirm机制设置
cd.getFuture().whenComplete(new BiConsumer<CorrelationData.Confirm, Throwable>() {
@Override
public void accept(CorrelationData.Confirm confirm, Throwable throwable) {
if (confirm.isAck()) {
log.info("消息投递成功!correlationData.id={},messageId={}", cd.getId(), cd.getReturned().getMessage().getMessageProperties().getMessageId());
} else {
String reason = confirm.getReason();
log.error("nack原因:{}", reason);
}
}
});
return true;
}
测试
将 routingKey 修改成错误的(我这边“test”才是对的),然后通过接口请求发送消息模拟,控制台日志如下:
04-26 23:53:22:624 INFO 35080 --- [nio-8082-exec-1] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [192.168.163.128:5672]
04-26 23:53:22:786 INFO 35080 --- [nio-8082-exec-1] o.s.a.r.c.CachingConnectionFactory : Created new connection: rabbitConnectionFactory#37348491:0/SimpleConnection@55b2b13e [delegate=amqp://rabbit@192.168.163.128:5672//mq-demo, localPort=56698]
04-26 23:53:22:842 INFO 35080 --- [68.163.128:5672] c.i.publisher.controller.StuController : 消息投递成功!correlationData.id=8501a153-5eff-464d-a14f-4504df0356d8,messageId=b4d36280-eb90-4e8b-ae12-63a1fce1c1bb
04-26 23:53:22:917 INFO 35080 --- [nectionFactory1] c.i.p.config.ReturnsCallbackConfig : returnsCallback回调信息:{"message":{"messageProperties":{"headers":{"spring_returned_message_correlation":"8501a153-5eff-464d-a14f-4504df0356d8","__TypeId__":"java.lang.String"},"timestamp":null,"messageId":"b4d36280-eb90-4e8b-ae12-63a1fce1c1bb","userId":null,"appId":null,"clusterId":null,"type":null,"correlationId":null,"replyTo":null,"contentType":"application/json","contentEncoding":"UTF-8","contentLength":0,"deliveryMode":null,"expiration":null,"priority":0,"redelivered":null,"receivedExchange":null,"receivedRoutingKey":null,"receivedUserId":null,"deliveryTag":0,"messageCount":null,"consumerTag":null,"consumerQueue":null,"receivedDelay":null,"receivedDeliveryMode":"PERSISTENT","finalRetryForMessageWithNoId":false,"publishSequenceNumber":0,"lastInBatch":false,"projectionUsed":false,"inferredArgumentType":null,"targetMethod":null,"targetBean":null,"replyToAddress":null,"delay":null,"xdeathHeader":null},"body":"IuS9oOWlvTPvvIzmnKzmrKHmmK/kuLrkuobmtYvor5Xlj5HpgIHogIXnoa7orqTmnLrliLYhIg=="},"replyCode":312,"replyText":"NO_ROUTE","exchange":"test.direct","routingKey":"test1"}
这样客户端就收到 MQ 的Ack回执和回调啦!