RabbitMQ—消息元数据解析指南

本文介绍了RabbitMQ的Java客户端实现,包含生产者和消费者代码示例。生产者通过建立连接、创建信道、声明队列,循环发送10条消息到"hello"队列;消费者同样建立连接后订阅该队列,通过DefaultConsumer接收并打印消息。文章重点解析了RabbitMQ的两个核心元数据:Envelope(包含投递标签、重投标志、交换机和路由键信息)和AMQP.BasicProperties(消息属性头,如内容类型、优先级等),详细说明了各参数含义及实际应用场景。这些元数据对消息路由、业务追踪和RPC通信等高级功能至关重要。

⽣产者代码


java 复制代码
package rabbitmq.simple;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class ProducerDemo {
    public static void main(String[] args) throws IOException, TimeoutException {
        //1. 建立连接
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("自己的服务器地址");
        connectionFactory.setPort(5672); //需要提前开放端口号
        connectionFactory.setUsername("账号名字");//账号
        connectionFactory.setPassword("密码");  //密码
        connectionFactory.setVirtualHost("主机名"); //虚拟主机
        Connection connection = connectionFactory.newConnection();
        //2. 开启信道
        Channel channel = connection.createChannel();
        //3. 声明交换机   使用内置的交换机
        //4. 声明队列
        /**
         * queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
         *                                  Map<String, Object> arguments)
         *  参数说明:
         *  queue: 队列名称
         *  durable: 可持久化
         *  exclusive: 是否独占
         *  autoDelete: 是否自动删除
         *  arguments: 参数
         */
        channel.queueDeclare("hello", true, false, false, null);
        //5. 发送消息
        /**
         * basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
         * 参数说明:
         * exchange: 交换机名称
         * routingKey: 内置交换机, routingkey和队列名称保持一致
         * props: 属性配置
         * body: 消息
         */
        for (int i = 0; i < 10; i++) {
            String msg = "hello rabbitmq~"+i;
            channel.basicPublish("","hello", null, msg.getBytes());
        }

        System.out.println("消息发送成功~");
        //6. 资源释放
        channel.close();
        connection.close();


    }
}

消费者代码

java 复制代码
package rabbitmq.simple;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class ConsumerDemo {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //1. 创建连接
       ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("自己的服务器地址");
        connectionFactory.setPort(5672); //需要提前开放端口号
        connectionFactory.setUsername("账号名字");//账号
        connectionFactory.setPassword("密码");  //密码
        connectionFactory.setVirtualHost("主机名"); //虚拟主机
        Connection connection = connectionFactory.newConnection();
        //2. 创建Channel
        Channel channel = connection.createChannel();
        //3. 声明队列(可以省略)
        channel.queueDeclare("hello",true, false, false, null);
        //4. 消费消息
        /**
         * basicConsume(String queue, boolean autoAck, Consumer callback)
         * 参数说明:
         * queue: 队列名称
         * autoAck: 是否自动确认
         * callback: 接收到消息后, 执行的逻辑
         */
        DefaultConsumer consumer = new DefaultConsumer(channel){
            //从队列中收到消息, 就会执行的方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("接收到消息:"+ new String(body));
//                System.out.println("接收到消息:"+ consumerTag);
//                System.out.println("接收到消息:"+ (String.valueOf(envelope)));
//                System.out.println("接收到消息:"+ properties );
            }
        };
        channel.basicConsume("hello", true, consumer);
        //等待程序执行完成
        Thread.sleep(2000);
        //5. 释放资源
        channel.close();
        connection.close();
    }
}

接收到消息:hello rabbitmq~9

接收到消息:amq.ctag-eK9h2CCuGOsETN7QBqO2xw

接收到消息:Envelope(deliveryTag=10, redeliver=false, exchange=, routingKey=hello)

接收到消息:#contentHeader<basic>(content-type=null, content-encoding=null, headers=null, delivery-mode=null, priority=null, correlation-id=null, reply-to=null, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null)

RabbitMQ 消息元数据详解

本文档详细介绍了 RabbitMQ 中两个核心的元数据对象:Envelope(物流信息)和 AMQP.BasicProperties(消息属性头)。

一、Envelope(信封)对象

Envelope 包含了 RabbitMQ 消息的"物流信息",用于追踪消息的投递状态和路径。

|-----------------|---------|------------------------------------------------------------------------------------------------------|
| 参数 | | 含义解释 |
| deliveryTag | 10 | 消息编号 这是第 10 条投递给你的消息。就像快递单号,用于确认收货(ACK)。 |
| redeliver | false | 是否重投 false = 这是第一次投递给你 true = 这条消息之前给过别的消费者(或之前给你但你没确认),现在重新投递 |
| exchange | ""(空) | 交换机名称 空字符串表示使用的是 内置默认交换机 (AMQP default)。生产者代码里 basicPublish("", "hello", ...) 第一个参数就是空字符串。 |
| routingKey | hello | 路由键 决定消息要送到哪个队列。在简单模式下,routingKey 通常等于队列名(hello)。就像写地址:"送到 hello 队列"。 |

🔍 详细解读

1. deliveryTag = 10
  • 作用:RabbitMQ 给这条消息打的序号(从 1 开始累加)。

  • 应用场景 :当你使用 手动确认autoAck=false)时,需要用这个编号告诉服务器:"第 10 条消息我处理完了,可以删了"。

java 复制代码
// 手动确认示例
channel.basicAck(envelope.getDeliveryTag(), false);
2. redeliver = false
  • 意味着什么:这条消息是"新鲜"的,第一次发给你。

  • 如果为 true:说明这条消息被"退件重发"了。可能原因:

    • 之前的消费者处理超时/崩溃,没有发送确认(ACK)。

    • RabbitMQ 把消息重新发给其他消费者(或再次发给你)。

3. exchange = ""
  • ""(空字符串)表示 默认交换机(Default Exchange)。

  • 这是 RabbitMQ 内置的直连交换机(direct exchange)。

  • 规则routingKey 必须完全匹配队列名才能路由。

4. routingKey = hello
  • 路由键:决定消息走哪条路。

  • 在默认交换机下,routingKey = 队列名。

  • 生产者代码里 basicPublish("", "hello", ...) 的第二个参数 "hello" 就是 routingKey

💡 一句话总结

Envelope 就是消息的"快递面单",告诉你:这是第 10 个包裹(deliveryTag=10),是第一次派送(redeliver=false),从默认站点发出(exchange=),目的地是 hello 队列(routingKey=hello)。而真正的"包裹内容"在 body 字节数组里!

二、AMQP.BasicProperties(消息属性头)

AMQP.BasicProperties 包含了消息的元数据信息(关于消息的数据,而非消息本身内容)。

如果在发送消息时第 3 个参数传了 null

java 复制代码
channel.basicPublish("", "hello", null, msg.getBytes());

那么这些属性都会是空的(null)。

📋 每个参数详解

|----------------------|---------|---------------|---------------------------------------------------|
| 参数名 | 当前值 | 含义 | 实际应用场景 |
| content-type | null | 内容类型(MIME类型) | 如 application/jsontext/plain。消费者收到后知道用什么格式解析 |
| content-encoding | null | 内容编码 | 如 gzip(压缩)、UTF-8。告诉消费者如何解码 |
| headers | null | 自定义头信息(Map类型) | 存自定义键值对,用于业务路由或过滤 |
| delivery-mode | null | 投递模式 | 1=非持久化(重启丢失),2=持久化(存磁盘,重启还在) |
| priority | null | 优先级 | 数字越大越优先(0-9)。VIP客户的消息插队处理 |
| correlation-id | null | 关联ID | 用于 RPC 模式。客户端发请求时带个唯一ID,服务端回复时带同样ID |
| reply-to | null | 回复队列名 | RPC场景中,告诉服务端:"处理完后把结果发到这个队列" |
| expiration | null | 过期时间(毫秒) | 如 60000 表示 1 分钟后若还没被消费,自动删除 |
| message-id | null | 消息唯一ID | 业务层面的消息编号,用于幂等性(防止重复消费) |
| timestamp | null | 时间戳 | 消息发送时间,用于日志追踪或延时计算 |
| type | null | 消息类型 | 业务类型标识,如 order.createduser.registered |
| user-id | null | 发送者ID | 验证消息发送者的身份 |
| app-id | null | 应用ID | 标识哪个应用发送的,如 order-service |
| cluster-id | null | 集群ID | 已废弃,基本不用 |

💡 实际使用示例

场景 1:发送 JSON 数据 + 自定义业务头
java 复制代码
// 生产者
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
    .contentType("application/json")           // 内容是 JSON
    .deliveryMode(2)                          // 持久化消息(重启不丢)
    .priority(5)                              // 优先级 5(较高)
    .messageId("ORDER-20240315-001")          // 业务消息ID
    .expiration("300000")                     // 5 分钟后过期
    .headers(Map.of("userId", "1001",         // 自定义头
                   "orderType", "vip"))
    .build();

channel.basicPublish("", "hello", props, jsonBytes);
场景 2:消费者读取这些属性
java 复制代码
@Override
public void handleDelivery(String consumerTag, Envelope envelope, 
                          AMQP.BasicProperties properties, byte[] body) {
    // 1. 判断内容类型
    if ("application/json".equals(properties.getContentType())) {
        // 按 JSON 解析
    }
    
    // 2. 获取业务 ID(幂等性校验)
    String msgId = properties.getMessageId();
    
    // 3. 获取自定义头
    Map<String, Object> headers = properties.getHeaders();
    if (headers != null) {
        String orderType = (String) headers.get("orderType");
    }
}

🎯 总结

这些属性都是消息的"标签",主要用于:

  1. 路由决策(headers、type)

  2. 消息特性(priority、expiration、delivery-mode)

  3. 业务追踪(message-id、correlation-id、timestamp)

  4. RPC 通信(reply-to、correlation-id)

入门示例传 null 是因为简单场景不需要高级特性,但在分布式微服务系统中,这些属性至关重要!

相关推荐
后端不背锅2 小时前
Redis 缓存穿透、击穿、雪崩:一次讲清楚
后端
用户6996228806052 小时前
PocketBase:3分钟搭建全功能后端的轻量级神器
后端
猹叉叉(学习版)2 小时前
【ASP.NET CORE】 11. SignalR
笔记·后端·c#·asp.net·.netcore
程序边界2 小时前
从MySQL到国产数据库的真实迁移笔记:那些坑爹的坑和意外的爽点
后端
qq5680180762 小时前
一个基于Spring Boot的简单网吧管理系统
java·spring boot·后端
hashiqimiya2 小时前
spring报错
java·后端·spring
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 基于Springboot的养老服务管理系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
包包5552 小时前
WxJava微信公众号开发实战
后端