尚硅谷rabbitmq 2024 消息可靠性答疑二 第22节

returnedMessage()只有失败才调用,confirm()成功失败了都会调用,为什么?

在RabbitMQ中,消息的确认和返回机制是为了确保消息的可靠传递和处理。`confirm`和`returnedMessage`方法的调用时机和目的不同,因此它们的行为也有所区别。

`ConfirmCallback`和`confirm`方法

**目的**:`ConfirmCallback`的主要目的是确认消息是否成功发布到交换机(Exchange)。

  • **成功(ack=true)**:当消息成功到达交换机时,会调用`confirm`方法,并且`ack`参数为`true`。

  • **失败(ack=false)**:当消息未能到达交换机时,会调用`confirm`方法,并且`ack`参数为`false`。失败的原因可能是交换机不存在或其他路由问题。

```java

@Override

public void confirm(CorrelationData correlationData, boolean ack, String cause) {

if (ack) {

log.info("Message confirmed successfully, correlationData: {}", correlationData);

} else {

log.warn("Message confirmation failed, correlationData: {}, cause: {}", correlationData, cause);

// 这里可以添加重试逻辑或其他处理

}

}

```

`ReturnsCallback`和`returnedMessage`方法

**目的**:`ReturnsCallback`的主要目的是处理那些成功到达交换机但无法路由到队列的消息。

  • **调用时机**:只有当消息无法路由到任何队列时,才会调用`returnedMessage`方法。这种情况通常发生在消息的路由键(Routing Key)与任何绑定的队列不匹配时。

```java

@Override

public void returnedMessage(ReturnedMessage returnedMessage) {

log.warn("Message returned: exchange: {}, routingKey: {}, replyCode: {}, replyText: {}, message: {}",

returnedMessage.getExchange(), returnedMessage.getRoutingKey(),

returnedMessage.getReplyCode(), returnedMessage.getReplyText(),

returnedMessage.getMessage());

// 这里可以添加处理逻辑,例如重发消息或记录日志

}

```

为什么`confirm`总是被调用,而`returnedMessage`只有在失败时调用?

  1. **消息发布确认(confirm)**:
  • **成功与失败**:`confirm`方法用于确认消息是否成功到达交换机。无论成功还是失败,都会调用这个方法,以便你能够记录日志、重试或进行其他处理。这提供了一个全局的确认机制,确保你知道消息的发布状态。

  • **可靠性**:这是消息发布的第一步确认,确保消息至少到达交换机。

  1. **消息返回(returnedMessage)**:
  • **仅失败时调用**:`returnedMessage`方法仅在消息无法路由到任何队列时调用。这是因为只有在这种情况下,消息才会被返回给发送者。成功路由的消息不需要调用这个方法,因为它们已经被正确处理。

  • **路由失败处理**:这是消息发布的第二步确认,确保消息不仅到达交换机,还能正确路由到队列。如果路由失败,你可以在这个方法中处理返回的消息,例如记录日志、重试发送或通知其他系统。

总结

  • **`confirm`方法**:总是被调用,用于确认消息是否成功到达交换机。无论成功还是失败,都会触发这个回调,以便你能够处理消息发布的结果。

  • **`returnedMessage`方法**:只有在消息无法路由到任何队列时才会调用,用于处理那些成功到达交换机但无法路由的消息。

这种设计确保了消息发布的可靠性和可追溯性,提供了两个层次的确认机制,分别处理消息发布和消息路由的不同阶段。

==========

rabbitTemplate.convertAndSend(EXCHANGE DIRECT, ROUTING KEy, obiect: "Message Test confirm~~~").

----convertAndSend ,convert?是转换了什么呢

在Spring AMQP中,`RabbitTemplate`的`convertAndSend`方法用于将消息转换为适合传输的格式,并发送到指定的交换机和路由键。`convert`部分指的是消息的转换过程,`send`部分指的是消息的发送过程。

`convertAndSend` 方法的作用

  1. **消息转换(Convert)**:
  • **对象到消息的转换**:`convertAndSend`方法会将你传入的对象(例如字符串、Java对象等)转换为`Message`对象。这个转换过程通常涉及将对象序列化为字节数组,并设置消息的头信息(如内容类型、编码等)。

  • **消息转换器(Message Converter)**:Spring AMQP提供了多种消息转换器(如`SimpleMessageConverter`、`Jackson2JsonMessageConverter`、`Jaxb2Marshaller`等),你可以根据需要选择或自定义消息转换器。

  1. **消息发送(Send)**:
  • **发送到交换机**:转换后的消息会被发送到指定的交换机(Exchange)。

  • **路由到队列**:交换机会根据指定的路由键(Routing Key)将消息路由到合适的队列。

示例代码

```java

import org.springframework.amqp.rabbit.core.RabbitTemplate;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

@Service

public class MyService {

@Autowired

private RabbitTemplate rabbitTemplate;

public void sendMessage() {

String exchange = "my.exchange";

String routingKey = "my.routingKey";

String message = "Message Test confirm~~~";

// 使用convertAndSend方法发送消息

rabbitTemplate.convertAndSend(exchange, routingKey, message);

}

}

```

消息转换器(Message Converter)

Spring AMQP提供了多种内置的消息转换器,你也可以自定义消息转换器。以下是一些常用的消息转换器:

  1. **SimpleMessageConverter**:
  • 默认的消息转换器,可以处理字符串、字节数组、序列化对象等。

  • 如果传入的是字符串,会将其转换为字节数组。

  1. **Jackson2JsonMessageConverter**:
  • 将Java对象转换为JSON格式的字节数组,适用于JSON序列化和反序列化。

  • 需要引入Jackson库。

  1. **Jaxb2Marshaller**:
  • 使用JAXB将Java对象转换为XML格式的字节数组,适用于XML序列化和反序列化。

自定义消息转换器

如果内置的消息转换器不能满足你的需求,你可以自定义消息转换器。以下是一个自定义消息转换器的示例:

```java

import org.springframework.amqp.core.Message;

import org.springframework.amqp.core.MessageProperties;

import org.springframework.amqp.support.converter.MessageConverter;

import org.springframework.stereotype.Component;

@Component

public class MyCustomMessageConverter implements MessageConverter {

@Override

public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {

// 自定义转换逻辑,例如将对象转换为字节数组

byte[] bytes = serializeObject(object);

return new Message(bytes, messageProperties);

}

@Override

public Object fromMessage(Message message) throws MessageConversionException {

// 自定义转换逻辑,例如将字节数组转换为对象

return deserializeObject(message.getBody());

}

private byte[] serializeObject(Object object) {

// 实现序列化逻辑

return object.toString().getBytes();

}

private Object deserializeObject(byte[] bytes) {

// 实现反序列化逻辑

return new String(bytes);

}

}

```

然后在配置类中注册自定义消息转换器:

```java

import org.springframework.amqp.rabbit.core.RabbitTemplate;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

@Configuration

public class RabbitConfig {

@Bean

public RabbitTemplate rabbitTemplate(RabbitTemplate rabbitTemplate, MyCustomMessageConverter myCustomMessageConverter) {

rabbitTemplate.setMessageConverter(myCustomMessageConverter);

return rabbitTemplate;

}

}

```

总结

  • **`convertAndSend`方法**:将传入的对象转换为`Message`对象,并发送到指定的交换机和路由键。

  • **消息转换器**:负责将对象序列化为字节数组,Spring AMQP提供了多种内置的消息转换器,你也可以自定义消息转换器。

  • **自定义消息转换器**:可以根据需要实现`MessageConverter`接口,提供自定义的序列化和反序列化逻辑。

通过理解消息转换和发送的过程,你可以更好地控制消息

================

  1. **消息发布确认(confirm)**:
  • **成功与失败**:`confirm`方法用于确认消息是否成功到达交换机。无论成功还是失败,都会调用这个方法,以便你能够记录日志、重试或进行其他处理。这提供了一个全局的确认机制,确保你知道消息的发布状态。

  • **可靠性**:这是消息发布的第一步确认,确保消息至少到达交换机。

  1. **消息返回(returnedMessage)**:
  • **仅失败时调用**:`returnedMessage`方法仅在消息无法路由到任何队列时调用。这是因为只有在这种情况下,消息才会被返回给发送者。成功路由的消息不需要调用这个方法,因为它们已经被正确处理。

  • **路由失败处理**:这是消息发布的第二步确认,确保消息不仅到达交换机,还能正确路由到队列。如果路由失败,你可以在这个方法中处理返回的消息,例如记录日志、重试发送或通知其他系统。

-----------这是rabbitmq里的,那kafka里面怎么做的呢?

在Kafka中,消息的确认和处理机制与RabbitMQ有所不同。以下是Kafka中对应的机制:

  1. **消息发布确认(Acks)**:
  • **成功与失败**:Kafka的生产者配置中有一个`acks`参数用于控制消息发布确认。常见的值有:

  • `acks=0`:生产者不会等待任何确认。消息发送后立即认为成功。

  • `acks=1`:领导者分区接收到消息后即确认,不等待副本确认。

  • `acks=all`(或`acks=-1`):所有副本都确认接收到消息后才认为成功。这是最可靠的设置,确保消息不会丢失。

  • **可靠性**:`acks=all`提供了最高的可靠性,确保消息被所有副本接收。

  1. **消息返回(Callback)**:
  • **成功与失败**:Kafka提供了一个回调机制来处理消息发送的结果。你可以在发送消息时指定一个`Callback`,它会在消息发送成功或失败时被调用。

  • **处理回调**:通过实现`Callback`接口的`onCompletion`方法,你可以处理成功和失败的情况。例如,记录日志、重试发送或通知其他系统。

以下是一个简单的示例代码,展示了如何在Kafka中使用`acks`和`Callback`:

```java

Properties props = new Properties();

props.put("bootstrap.servers", "localhost:9092");

props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");

props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

props.put("acks", "all"); // 设置消息确认机制

KafkaProducer<String, String> producer = new KafkaProducer<>(props);

ProducerRecord<String, String> record = new ProducerRecord<>("topic-name", "key", "value");

producer.send(record, new Callback() {

@Override

public void onCompletion(RecordMetadata metadata, Exception exception) {

if (exception == null) {

// 消息发送成功

System.out.println("Message sent successfully to topic " + metadata.topic() + " partition " + metadata.partition() + " offset " + metadata.offset());

} else {

// 消息发送失败

exception.printStackTrace();

// 处理失败情况,例如重试发送、记录日志等

}

}

});

producer.close();

```

通过这种方式,Kafka提供了灵活的消息确认和处理机制,确保消息的可靠传递和处理。

相关推荐
疯一样的码农8 分钟前
Spring Boot Starter Parent介绍
java·spring boot·后端
iQM7510 分钟前
Spring Boot集成RBloomFilter快速入门Demo
java·spring boot·spring
爱上语文13 分钟前
Springboot 阿里云对象存储OSS 工具类
java·开发语言·spring boot·后端·阿里云
代码代码快快显灵3 小时前
java之异常处理
java·开发语言
茶馆大橘3 小时前
Spring Validation —— 参数校验框架
java·后端·学习·spring
阿望要努力上研究生5 小时前
若依项目搭建(黑马经验)
java·redis·node.js·maven·管理系统
一只脑洞君5 小时前
Kubernetes(K8s)的简介
java·容器·kubernetes
zygswo5 小时前
程序猿成长之路之设计模式篇——设计模式简介
java·设计模式
除了代码啥也不会6 小时前
springboot项目发送邮件
java·spring boot·spring