尚硅谷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提供了灵活的消息确认和处理机制,确保消息的可靠传递和处理。

相关推荐
Q_19284999062 分钟前
基于Spring Boot的摄影器材租赁回收系统
java·spring boot·后端
Code_流苏5 分钟前
VSCode搭建Java开发环境 2024保姆级安装教程(Java环境搭建+VSCode安装+运行测试+背景图设置)
java·ide·vscode·搭建·java开发环境
禁默1 小时前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Code哈哈笑1 小时前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
gb42152871 小时前
springboot中Jackson库和jsonpath库的区别和联系。
java·spring boot·后端
程序猿进阶1 小时前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
zfoo-framework1 小时前
【jenkins插件】
java
风_流沙1 小时前
java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
java·数据库·elasticsearch