RabbitMQ 学习

RabbitMQ 是一个开源的、基于 Erlang 语言实现的消息队列中间件,使用高级消息队列协议(AMQP)进行通信。它在分布式系统中用于解耦应用程序、提升异步通信能力、提高系统可扩展性与可靠性。

传统的组件之间直接调用(REST、RPC 等)导致: 高耗耗,并发性差,系统耦合性差,故障传播,需要一种可靠的、异步的、组件解耦的中间件。RabbitMQ 就是在这样的需求下,基于 AMQP 标准,为解决分布式应用的消息通信提供稳定性和扩展性。

RabbitMQ 消息队列的使用场景非常广泛,核心作用在于解耦、削峰、异步处理。下面是一个典型的使用场景示例:

复制代码
# 📦 使用场景:下单后异步发送短信通知

 场景描述:

  用户在电商网站下单后,系统需要给用户发送一条"下单成功"的短信。传统做法是下单成功后立刻调用短信接口发送。但如果短信服务延迟或失败,会直接影响用户下单体验。

 ✅ 引入 RabbitMQ 解决方式:
  1.用户下单成功后,系统将"发送短信任务"放入 RabbitMQ 的队列中;
  2.短信服务是一个独立的消费者进程,监听这个队列;
  3.一旦有消息进入队列,消费者接收并调用短信服务发送短信。

 🎯 优点:
  • 解耦合:下单逻辑与短信逻辑分离;
  • 提高性能:下单接口响应快,不必等待短信接口;
  • 具备容错性:如果短信服务临时宕机,消息仍保存在队列中,不会丢失。

RabbitMQ 快速实践

一.普通安装

RabbitMQ安装配置过程详解(Linux版)

1、介绍:

本次RabbitMQ安装环境相关信息:

Linux CentOS 7版本

erlang-21.3-1.el7.x86_64.rpm

rabbitmq-server-3.8.8-1.el7.noarch.rpm

RabbitMQ的底层源码是基于erlang语言开发的,因此安装rabbitMQ需要依赖erlang语言环境.

2、下载安装程序

当erlang和rabbitmq所安装的版本不对应时,可能会无法正常运行,为此安装所需要的Linux版本的erlang和rabbitmq对应安装包已经整理于网盘中,下载地址如下,若提取码失效,还请及时联系:

链接:https://pan.baidu.com/s/1NxK78QASAvlM48vkU4FXAw

提取码:x6ld

将下载好的压缩包通过Xftp上传至/home/rabbitmq 目录下(如果没有 rabbitmq 需要自己创建)

3、文件安装

3.1 rpm方式安装erlang:
bash 复制代码
rpm -ivh erlang-21.3-1.el7.x86_64.rpm
安装socat 依赖
bash 复制代码
yum -y install socat

在通过yum安装时,可能会由于源的问题,centos7目前无法通过yum进行联网安装软件:具体解决方法如下:

bash 复制代码
# 1、将yum的源改成阿里云的,直接在命令行输入:
	curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

# 2、运行 yum clean all
	yum clean all

# 3、生成yum缓存
	yum makecache
	
# 4、 可以通过yum repolist来查询yum的状态
	yum repolist

yum问题解决之后,运行 yum -y install socat,安装成功

bash 复制代码
yum -y install socat
安装RabbitMQ
bash 复制代码
rpm -ivh rabbitmq-server-3.8.8-1.el7.noarch.rpm

RabbitMQ的启动 停止命令:

bash 复制代码
# 添加开机启动 RabbitMQ 服务
chkconfig rabbitmq-server on

# 启动 RabbitMQ 服务
/sbin/service rabbitmq-server start 

# 停止服务(选择执行)
/sbin/service rabbitmq-server stop

# 查看服务状态
/sbin/service rabbitmq-server status

在启动RabbtMQ之前,开启web插件管理,开启之后可以通过http://localhost:15672 来访问rabbitMQ的页面

开启 web 管理插件

rabbitmq-plugins enable rabbitmq_management

登录前端控制界面

再登录之前,先确保RabbitMQ的服务是出于开启的状态,可以通过上述的服务器查看和开启命令自行查看。

由于我的Linux部署在阿里云服务器上,访问地址为 阿里云的公网ip地址:15672端口,默认初始化用户名和密码均为guest,

此外,由于是远程登录阿里云服务器,需要设置阿里云安全组开启15672端口,开启之后便可正常登录。在登录的时候会出现权限问题,无法登录:

添加一个新的用户

出现上述登录时权限问题,需要创建一个新的用户,并设置用户角色和权限,具体步骤如下:

bash 复制代码
# 创建账号 设置用户名和密码
rabbitmqctl add_user admin 123

# 设置用户角色
rabbitmqctl set_user_tags admin administrator

# 设置用户权限 set_permissions [-p <vhostpath>] <user> <conf> <write> <read>
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
# 上述命令使得用户 user_admin 具有/vhost1 这个 virtual host 中所有资源的配置、写、读权限

# 当前用户和角色
rabbitmqctl list_users

使用新建的用户admin进行登录

附加命令:

bash 复制代码
# 关闭应用的命令为
rabbitmqctl stop_app

# 清除的命令为
rabbitmqctl reset

# 重新启动命令为
rabbitmqctl start_app

二. RabbitMQ Docker 快速部署指南

复制代码
# 这里下载最新的,如果需要指定版本,后缀指定即可

  docker search rabbitmq
 docker pull rabbitmq 
 docker pull rabbitmq:指定的版本

# 启动 mq 【-v 将文件挂载至宿主机器上】

 docker run \
   --privileged=true \
   -d \
   -p 5672:5672 \
   -p 15672:15672 \
   --name rabbitmq \
   --restart=always \
   --hostname rabbitmq \
   rabbitmq

  #参数说明:
  #--privileged=true:赋予容器特权模式(有安全隐患,生产环境慎用)
  #-d:以守护进程方式运行容器
  #-p 5672:5672:映射 AMQP 协议端口
  #-p 15672:15672:映射管理界面端口
  #--name rabbitmq:指定容器名称
  #--restart=always:设置容器自动重启策略
  #--hostname:设置容器主机名

# 启动容器后,进入容器启动管理页面

 docker exec -it rabbitmq rabbitmq-plugins enable rabbitmq_management

# 启用管理界面的指标收集功能,然后重启容器使配置生效

 docker exec -it rabbitmq bash
 cd /etc/rabbitmq/conf.d/
 echo management_agent.disable_metrics_collector = false > 20-management_agent.disable_metrics_collector.conf
 exit 
 docker restart rabbitmq

# 浏览器访问 http://127.0.0.1:15672/#/
# 初始账号密码 guest guest

以 Spring Boot + RabbitMQ 为例:

复制代码
# Maven 依赖
 
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-amqp</artifactId>
 </dependency>

# application.yml 配置

 spring:
    rabbitmq:
      host: localhost
      port: 5672
     username: guest
     password: guest
      # virtual-host: my_vhost

 # 消息发送者

   @Service
  public class Sender {
      @Autowired
      private RabbitTemplate rabbitTemplate;

      public void send(String message) {
          rabbitTemplate.convertAndSend("testQueue", message);
      }
  }

# 消息接收者

  @Component
  public class Receiver {

      @RabbitListener(queues = "testQueue")
      public void receive(String message) {
          System.out.println("Received: " + message);
      }
  }

# 初始化队列

  @Configuration
  public class RabbitConfig {
      @Bean
      public Queue testQueue() {
          return new Queue("testQueue");
      }
  }

MQ常用命令

复制代码
# RabbitMQ 服务管理命令(需在容器内执行)

# 1. 启停服务

 rabbitmq-server    # 启动服务(容器内通常不需要手动执行)
 rabbitmqctl stop   # 停止服务

# 2. 插件管理

 rabbitmq-plugins list                         # 列出所有插件
 rabbitmq-plugins enable rabbitmq_management   # 启用管理界面
 rabbitmq-plugins disable <插件名>              # 禁用插件

# 3. 状态检查

 rabbitmqctl status                # 查看服务状态
 rabbitmqctl cluster_status        # 查看集群状态

##################### 用户与权限管理 #################

# 1. 用户操作

 rabbitmqctl list_users                          # 列出所有用户
 rabbitmqctl add_user <用户名> <密码>              # 创建用户
 rabbitmqctl delete_user <用户名>                  # 删除用户
 rabbitmqctl change_password <用户名> <新密码>      # 修改密码

# 2. 设置用户角色(Tags)

 RabbitMQ 角色分为以下几种:
  administrator:超级管理员(可管理所有资源)
  monitoring:监控者(可查看所有状态)
  policymaker:策略管理者(可配置策略)
  management:普通管理者(基础操作权限)
  自定义角色(如 producer/consumer)

 # 设置为管理员角色(最高权限)
 rabbitmqctl set_user_tags admin administrator

 # 如果需要多个角色(用空格分隔)
 rabbitmqctl set_user_tags admin monitoring policymaker

# 3. 权限控制
# rabbitmqctl set_permissions -p <虚拟主机> <用户名> <配置权限> <写入权限> <读取权限>

 rabbitmqctl list_permissions [-p <vhost>]                      # 查看权限
 rabbitmqctl set_permissions -p <vhost> <用户> ".*" ".*" ".*"    # 授予权限
 rabbitmqctl clear_permissions -p <vhost> <用户>                 # 清除权限 

 权限说明:
  ".*":通配符表示所有资源
  "^queue\.":正则表达式匹配特定资源(如所有队列)

# 4. 验证用户和权限

 # 列出所有用户(显示用户名和角色)
 rabbitmqctl list_users

 # 查看特定用户的权限
 rabbitmqctl list_permissions -p "/" admin

 # 查看所有虚拟主机的权限
 rabbitmqctl list_permissions

##################### 虚拟主机(VHost)管理 #################

 rabbitmqctl list_vhosts                   # 列出所有虚拟主机
 rabbitmqctl add_vhost <vhost名>           # 创建虚拟主机
 rabbitmqctl delete_vhost <vhost名>        # 删除虚拟主机

##################### 队列与交换机管理 #################

# 1. 查看队列/交换机

 rabbitmqctl list_queues [-p <vhost>]      # 列出队列
 rabbitmqctl list_exchanges [-p <vhost>]   # 列出交换机
 rabbitmqctl list_bindings [-p <vhost>]    # 列出绑定关系

# 2. 清理队列

 rabbitmqctl purge_queue <队列名>          # 清空队列中的消息

##################### 其他 #################

# 1. 重置节点(危险操作!)

 rabbitmqctl reset    # 重置节点(会删除所有数据和配置)

# 2. 日志查看

 tail -f /var/log/rabbitmq/rabbitmq.log   # 查看日志(容器内路径)


##################### HTTP API 管理(无需进入容器) #################
# 通过 curl 调用管理 API(需先启用 rabbitmq_management 插件):

 curl -u admin:admin http://localhost:15672/api/queues  # 获取队列列表

# 常见使用场景示例:
# 1. 创建用户并授权:

 rabbitmqctl add_user user1 pass123
 rabbitmqctl set_permissions -p / user1 ".*" ".*" ".*"

# 2. 监控队列积压消息数:

 rabbitmqctl list_queues name messages_ready

# 备份与恢复:

 备份定义:rabbitmqctl export_definitions /backup/rabbitmq_defs.json
 恢复定义:rabbitmqctl import_definitions /backup/rabbitmq_defs.json

RabbitMQ 核心概念及关系

复制代码
# 1. Queue(队列)

 • 消息的最终存储地点。
 • 消费者只能从队列中获取消息。
 • 每条消息只会被一个消费者获取(除非使用特殊机制如镜像队列)。

# 2. Exchange(交换机)

 • 接收生产者发送的消息,并根据路由规则转发到一个或多个队列。
 • 不存储消息,只负责转发。

 • 有四种类型:
  • fanout:广播消息到所有绑定队列
  • direct:根据精确的 routing key 匹配转发
  • topic:支持模糊匹配的 routing key(带 * 和 #)
  • headers:基于消息 header 的键值匹配(较少使用)

# 3. Routing Key(路由键)

 • 是一段字符串,生产者在发送消息时指定。
 • 交换机根据 routing key 与绑定关系(binding)进行匹配,将消息转发到相应队列。

# 4. Binding(绑定)

 • 是交换机与队列之间建立的连接关系。
 • 绑定时可以指定 routing key 或匹配模式(取决于交换机类型)。
 • 一台交换机可以绑定多个队列。

# 5. Producer(生产者)

 • 向交换机发送消息,必须指定:
  • 目标交换机
  • routing key
  • 消息内容(body)

# 6. Consumer(消费者)

 • 从队列中消费消息。
 • 每个消费者监听一个或多个队列。

# 7. Virtual Host(虚拟主机)

 • 类似于命名空间,用于隔离资源。
 • 一个 RabbitMQ 实例中可以有多个 vhost,每个 vhost 中有独立的交换机、队列、绑定等。


# 8. Message(消息)

 • 消息体是实际传输的数据内容(通常是字符串、JSON、二进制等)。
 • 消息中还包含 headers、properties(比如持久性、优先级、过期时间等)。

# 9. Acknowledgment(消息确认)

 • 消费者从队列中获取消息后需要确认(ack),表示处理完成。
 • 如果未 ack,消息可以重新投递。
 • 支持自动确认或手动确认。

# 10. Durability(持久性)

 • 队列和消息都可以设置是否持久化:
  • 队列 durable = true → RabbitMQ 重启后队列仍在。
  • 消息 delivery_mode = 2 → 消息将写入磁盘。


# 🔁 它们之间的关系

 [Producer] --(routingKey)--> [Exchange] --(binding with routingKey)--> [Queue] --> [Consumer]

 简要流程:
  1.Producer 向 Exchange 发送消息,指定 routing key。
  2.Exchange 根据自身类型和绑定规则,决定将消息路由到哪些 Queue。
  3.Queue 存储消息,等待 Consumer 消费。
  4.Consumer 从 Queue 中拉取或订阅消息,处理后确认(ack)。

RabbitMQ 中 4 种交换机类型(Exchange Type)

类型 描述 路由方式 是否依赖 routingKey 多播支持 匹配灵活性
fanout 广播式 所有绑定的队列都接收消息
direct 精确路由 routingKey 完全匹配 精确匹配
topic 模糊匹配路由 routingKey 模式匹配 可多个
headers 基于消息 headers 匹配 匹配 headers 的键值对 非常高

RabbitMQ 消息运行模式的七种模型

复制代码
# 🧩 1. 简单模式(Simple / Hello World)

 简介:
  最基础的一种模式,一个生产者发送消息到队列,一个消费者从队列中接收消息。

 特点:
  • 一对一通信
  • 没有 Exchange(使用默认的)
  • 队列名称需匹配

 场景:
  适合快速测试和入门练习,或简单的一对一消息处理。

  Producer --> [Queue] --> Consumer

# 🧩 2. 工作队列模式(Work Queues / Task Queue)

 简介:
  多个消费者从同一个队列获取任务,实现负载均衡。

 特点:
  • 一个队列,多个消费者
  • 每条消息只会被一个消费者处理
  • 支持消息应答(ack)

 场景:
  适用于任务分发、后台异步处理,如图片处理、邮件发送等。

  Producer --> [Queue] --> Consumer1
                          --> Consumer2
                          --> Consumer3


# 🧩 3. 发布/订阅模式(Publish/Subscribe / Fanout Exchange)

 简介:
  一个生产者将消息广播给多个队列,所有绑定的消费者都能收到消息。

 特点:
  • 使用 Fanout 类型 Exchange
  • 每个队列绑定到 Exchange 上
  • 消息发送到所有绑定的队列

 场景:
  适用于广播通知,比如系统日志同步、多个系统接收同一份数据等。

 Producer --> [Fanout Exchange]
                 |        |
            [Queue1]  [Queue2]
               |          |
           Consumer1  Consumer2


# 🧩 4. 路由模式(Routing / Direct Exchange)

 简介:
  生产者根据路由键(Routing Key)将消息投递到不同的队列,消费者只接收指定路由键的消息。

 特点:
  • 使用 Direct 类型 Exchange
  • 队列根据绑定的 routing key 接收消息

 场景:
  日志系统分类投递,比如"error"、"info"、"warning"等级日志只发送给指定服务。

 Producer --[Direct Exchange]--(key="error")--> [Queue1] --> Consumer1
                             --(key="info")-->  [Queue2] --> Consumer2


# 🧩 5. 通配符模式(Topics / Topic Exchange)

 简介:
  在路由模式基础上加入通配符匹配机制,增强路由灵活性。

 特点:
  • 使用 Topic 类型 Exchange
  • Routing Key 支持 *(匹配一个词)和 #(匹配零个或多个词)

 场景:
  适用于需要更复杂的路由规则,如新闻订阅、设备数据分组等。

 Producer --[Topic Exchange]--(key="user.*")--> [Queue1]
                               (key="user.#")--> [Queue2]


# 🧩 6. RPC 模式(Remote Procedure Call)

 简介:
  使用 RabbitMQ 实现远程调用请求/响应模式。客户端发送请求,服务端处理后响应。

 特点:
  • 客户端发送请求消息,附带回调队列和 correlationId
  • 服务端返回响应到回调队列
  • 客户端等待响应

 场景:
  实现微服务之间的 RPC 通信,如获取用户信息、远程调用计算服务等。

 Client --> [Queue: rpc_request] --> Server
 Server --> [Queue: callback_queue] --> Client


# 🧩 7. 发布确认(Publisher Confirms)

 简介:
  用于确保消息可靠性投递的机制,确保消息从生产者成功到达 Broker。

 特点:
  • 生产者发送消息后可以开启 confirm 模式
  • Broker 接收到消息后会返回 ack/nack
  • 可以结合批量确认或异步确认机制

 场景:
  适用于对消息可靠性要求高的场景,如金融交易、订单系统等。

 Producer --[Confirm Select模式]--> Exchange
   <-- Ack / Nack (Broker确认投递成功与否)

RabbitMQ 的 Java 和 Spring 示例

在 RabbitMQ 的 Java 客户端(amqp-client)中,几个核心类/接口是必须熟悉的,它们是构建生产者、消费者、交换机、队列等功能的基础。

RabbitMQ Java 客户端核心对象及 API 说明

类/接口 作用简述
ConnectionFactory 构建连接的工厂类,用于设置主机、端口、用户名、虚拟主机等
Connection 表示客户端到 RabbitMQ 的一个连接
Channel 通信通道,用于声明交换机/队列、发送消息、消费消息等
BuiltinExchangeType 枚举类型,指定交换机类型:DIRECT、TOPIC、FANOUT、HEADERS
AMQP.BasicProperties 消息的元数据(持久化、优先级、headers 等)
复制代码
// Maven 依赖

<dependency>
  <groupId>com.rabbitmq</groupId>
  <artifactId>amqp-client</artifactId>
  <version>5.20.0</version>
</dependency>

// 🔧 核心 API 常用用法

// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setUsername("guest");
factory.setPassword("guest");

// 建立连接
Connection connection = factory.newConnection();

// 创建通道
Channel channel = connection.createChannel();

// 声明交换机
channel.exchangeDeclare("my-exchange", BuiltinExchangeType.DIRECT, true);

// 声明队列
channel.queueDeclare("my-queue", true, false, false, null);

// 队列绑定到交换机
channel.queueBind("my-queue", "my-exchange", "my.routing.key");

// 发布消息
channel.basicPublish("my-exchange", "my.routing.key", null, "Hello".getBytes());

✅ 4种交换机的使用方式(含代码 + 路由说明)

复制代码
# 🧰 公共工具类(连接工具)

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

 public class RabbitUtil {
     public static Connection getConnection() throws Exception {
         ConnectionFactory factory = new ConnectionFactory();
         factory.setHost("localhost");       // RabbitMQ 主机地址
         factory.setPort(5672);              // 默认端口
         factory.setUsername("guest");       // 默认用户名
         factory.setPassword("guest");       // 默认密码
         factory.setVirtualHost("/");        // 默认虚拟主机
         return factory.newConnection();
     }
 }

# 1️⃣  Fanout Exchange(广播交换机)

 import com.rabbitmq.client.*;

 public class FanoutExample {
     public static void main(String[] args) throws Exception {
         Connection connection = RabbitUtil.getConnection();
         Channel channel = connection.createChannel();

         String exchangeName = "ex.fanout";
         String queue1 = "fanout.queue.1";
         String queue2 = "fanout.queue.2";

         // 声明交换机:类型为 FANOUT(广播)
         channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT, true);

         // 声明两个队列
         channel.queueDeclare(queue1, true, false, false, null);
         channel.queueDeclare(queue2, true, false, false, null);

         // 将两个队列绑定到广播交换机(不需要 routing key)
         channel.queueBind(queue1, exchangeName, "");
         channel.queueBind(queue2, exchangeName, "");

         // 发布消息:routingKey 无效,使用空字符串
         String msg = "广播通知:系统即将维护!";
         channel.basicPublish(exchangeName, "", null, msg.getBytes());

         System.out.println("Fanout 消息发送成功!");
         channel.close();
         connection.close();
     }
 }

# 2️⃣ Direct Exchange(直连交换机)

 import com.rabbitmq.client.*;

 public class DirectExample {
     public static void main(String[] args) throws Exception {
         Connection connection = RabbitUtil.getConnection();
         Channel channel = connection.createChannel();

         String exchangeName = "ex.direct";
         String queue = "direct.queue.error";

         // 声明交换机:类型为 DIRECT
         channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT, true);

         // 声明队列
         channel.queueDeclare(queue, true, false, false, null);

         // 绑定:指定 routingKey 为 "error"
         channel.queueBind(queue, exchangeName, "error");

         // 发布一条错误日志
         String msg = "ERROR:服务崩溃了!";
         channel.basicPublish(exchangeName, "error", null, msg.getBytes());

         System.out.println("Direct 消息发送成功!");
         channel.close();
         connection.close();
     }
 }

# 3️⃣ Topic Exchange(主题交换机)

 import com.rabbitmq.client.*;

 public class TopicExample {
     public static void main(String[] args) throws Exception {
         Connection connection = RabbitUtil.getConnection();
         Channel channel = connection.createChannel();

         String exchangeName = "ex.topic";
         String queue = "topic.queue.orders";

         // 声明交换机:类型为 TOPIC
         channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC, true);

         // 声明队列
         channel.queueDeclare(queue, true, false, false, null);

         // 绑定:接收所有 order 开头的消息(如 order.create, order.pay)
         channel.queueBind(queue, exchangeName, "order.*");

         // 发布一条订单创建的消息
         String msg = "订单创建成功:#12345";
         channel.basicPublish(exchangeName, "order.create", null, msg.getBytes());

         System.out.println("Topic 消息发送成功!");
         channel.close();
         connection.close();
     }
 }

# 4️⃣ Headers Exchange(头部交换机)

 import com.rabbitmq.client.*;

 import java.util.HashMap;
 import java.util.Map;

 public class HeadersExample {
     public static void main(String[] args) throws Exception {
         Connection connection = RabbitUtil.getConnection();
         Channel channel = connection.createChannel();

         String exchangeName = "ex.headers";
         String queue = "headers.queue";

         // 声明交换机:类型为 HEADERS
         channel.exchangeDeclare(exchangeName, BuiltinExchangeType.HEADERS, true);

         // 声明队列
         channel.queueDeclare(queue, true, false, false, null);

         // 设置绑定时要求 header 匹配所有条件
         Map<String, Object> bindingArgs = new HashMap<>();
         bindingArgs.put("x-match", "all"); // "all" 表示所有 header 都必须匹配
         bindingArgs.put("format", "pdf");
         bindingArgs.put("type", "report");

         // 绑定队列到交换机,带绑定参数
         channel.queueBind(queue, exchangeName, "", bindingArgs);

         // 发送消息时设置 headers
         AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
                 .headers(Map.of("format", "pdf", "type", "report"))
                 .build();

         String msg = "PDF 报告已生成";
         channel.basicPublish(exchangeName, "", props, msg.getBytes());

         System.out.println("Headers 消息发送成功!");
         channel.close();
         connection.close();
     }
 }

在 Spring 中使用 RabbitMQ,我们通常借助 Spring AMQP 框架(它是基于 spring-rabbit 的封装)。它极大简化了连接配置、交换机/队列声明、消息发送与接收等操作。

🧩 一、Spring 中使用 RabbitMQ 的方式

复制代码
# 1️⃣ 引入依赖

 <!-- Maven 依赖 -->
 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-amqp</artifactId>
 </dependency>

# 2️⃣ application.yml 配置

 spring:
   rabbitmq:
     host: localhost
     port: 5672
     username: guest
     password: guest
     virtual-host: /
     listener:
       simple:
         acknowledge-mode: manual  # 启用手动确认
         prefetch: 1               # 每次只拉取一条消息处理
     publisher-confirm-type: correlated # 开启发布确认(confirm)
     publisher-returns: true            # 开启返回监听(return)

🚀 二、交换机、队列和绑定关系的声明(持久化)

Spring 提供声明式写法,所有声明的队列/交换机默认是持久化的(除非你设置 durable = false)

复制代码
@Configuration
publicclass RabbitConfig {

    // 1. 声明交换机(Topic类型)
    @Bean
    public TopicExchange topicExchange() {
        returnnew TopicExchange("ex.topic", true, false);
    }

    // 2. 声明队列
    @Bean
    public Queue orderQueue() {
        returnnew Queue("queue.order", true); // durable = true 表示持久化
    }

    // 3. 绑定交换机和队列
    @Bean
    public Binding binding() {
        return BindingBuilder.bind(orderQueue())
                .to(topicExchange())
                .with("order.#"); // 通配 routingKey
    }
}

📬 三、发送消息(带持久化标志 & 确认)

复制代码
@Service
publicclass OrderProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    // 消息发送(持久化 + 回调确认)
    public void sendOrder(String orderJson) {
        MessageProperties props = new MessageProperties();
        props.setDeliveryMode(MessageDeliveryMode.PERSISTENT); // 消息持久化
        Message message = new Message(orderJson.getBytes(), props);

        rabbitTemplate.convertAndSend("ex.topic", "order.created", message);
    }
}

@Component
publicclass ConfirmCallbackHandler implements RabbitTemplate.ConfirmCallback {

    @Autowired
    public ConfirmCallbackHandler(RabbitTemplate rabbitTemplate) {
        rabbitTemplate.setConfirmCallback(this); // 注入回调
    }
    
    // **✅ 发布确认回调(confirm)**
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            System.out.println("消息发送成功!");
        } else {
            System.out.println("消息发送失败,原因:" + cause);
        }
    }
    
    // ✅ Return 回调(不可路由)
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText,
                                String exchange, String routingKey) {
        System.out.println("消息无法投递:" + new String(message.getBody()));
    }
}

🎯 四、消费者(消息监听器)消费 + 手动确认

复制代码
@Component
publicclass OrderConsumer {

    @RabbitListener(queues = "queue.order", ackMode = "MANUAL")
    public void onMessage(Message message, Channel channel) throws IOException {
        try {
            String msg = new String(message.getBody());
            System.out.println("收到订单消息:" + msg);

            // 处理逻辑成功后手动确认
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            // 出错则拒绝消息,可选择重回队列或丢弃
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }
}

📦 五、消息持久化相关说明

复制代码
  • 交换机持久化:声明时设置 durable = true
  • 队列持久化:声明时设置 durable = true
  • 消息持久化:发送时设置 deliveryMode = MessageDeliveryMode.PERSISTENT
 
 📌 三者必须同时设置才真正实现消息不丢(即使 RabbitMQ 重启也能恢复)。

队列优先级(Priority Queue) 和 死信队列(Dead Letter Queue,简称 DLQ)

📌 一、优先级队列(Priority Queue)

复制代码
# 📌 1. 优先级队列(Priority Queue)

 RabbitMQ 支持基于消息优先级的队列,即队列中的消息将按照优先级值进行排序,高优先级的消息会被优先消费。

 🧠 本质上:RabbitMQ 的优先级队列基于优先级值进行"排序投递",不是严格排序,也不是抢占式消费。

# ✅ 2. 应用场景

 • 客服系统中,VIP 用户消息优先处理
 • 订单系统中,紧急订单优先处理
 • 报警系统中,高等级报警优先发出

# ✅ 3. RabbitMQ 中如何声明优先级队列

 优先级范围:默认支持 0~255,默认最大值为 10(需显式声明)

# ✅ 4. Spring 配置

 @Bean
 public Queue priorityQueue() {
     Map<String, Object> args = new HashMap<>();
     args.put("x-max-priority", 10); // 最大优先级设为 10

     return new Queue("priority.queue", true, false, false, args);
 }

# ✅ 5. 发送消息时设置优先级:

 rabbitTemplate.convertAndSend("priority.queue", "普通消息",
     message -> {
         message.getMessageProperties().setPriority(1); // 设置优先级为1
         return message;
     });

 rabbitTemplate.convertAndSend("priority.queue", "高优先级消息",
     message -> {
         message.getMessageProperties().setPriority(9); // 高优先级
         return message;
     });

💀 二、死信队列(Dead Letter Queue, DLQ)

复制代码
# **💀** 1. 死信队列(Dead Letter Queue, DLQ)

 死信队列用于处理失败或异常的消息。当一条消息因某种原因无法被正常消费时(如拒绝、过期、队列满),RabbitMQ 会将其转发到死信交换机(Dead Letter Exchange, DLX),再由 DLX 投递到对应的死信队列。

# ✅ 2. 死信的触发条件

 • 消费者调用 basicReject() 或 basicNack() 且 requeue = false
 • 消息过期(TTL)
 • 队列已满(达到最大长度)

# ✅ 3. 使用方式(Spring)

 // 步骤一:声明普通队列,并绑定死信交换机

 @Bean
 public Queue normalQueue() {
     Map<String, Object> args = new HashMap<>();
     args.put("x-dead-letter-exchange", "dlx.exchange");      // 绑定死信交换机
     args.put("x-dead-letter-routing-key", "dlx.key");        // 指定路由 key
     args.put("x-message-ttl", 10000);                        // 消息 10 秒过期(可选)

     return new Queue("normal.queue", true, false, false, args);
 }

 // 步骤二:声明死信交换机和死信队列

 @Bean
 public DirectExchange dlxExchange() {
     return new DirectExchange("dlx.exchange");
 }

 @Bean
 public Queue dlxQueue() {
     return new Queue("dead.queue", true);
 }

 @Bean
 public Binding dlxBinding() {
     return BindingBuilder.bind(dlxQueue())
             .to(dlxExchange())
             .with("dlx.key");
 }


# ✅ 4. 消费者中拒绝消息(可触发死信)

 @RabbitListener(queues = "normal.queue")
 public void handle(String msg, Channel channel, Message message) throws IOException {
     System.out.println("收到消息:" + msg);

     if (msg.contains("错误")) {
         // 拒绝消息,不重回队列,消息进入 DLQ
         channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
     } else {
         // 正常确认
         channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
     }
 }

# 完整流程示意图(文字版)

 [发送消息]
      ↓
 [普通交换机] --- routingKey ---→ [普通队列 normal.queue]
      ↓ 拒绝、过期、满
 [死信交换机 dlx.exchange] --- routingKey → [死信队列 dead.queue]

Rabbitmq插件

RabbitMQ 提供了很多强大的 插件(Plugins),可以用来扩展其功能,如:管理界面、消息追踪、限流控制、延迟队列、集群管理等等。

插件名称 作用简介
rabbitmq_management 提供 Web 管理界面(默认 15672 端口)
rabbitmq_delayed_message_exchange 延迟队列实现方式
rabbitmq_shovel 跨实例/数据中心消息复制或转发
rabbitmq_federation 多数据中心消息联邦(类似同步)
rabbitmq_prometheus 暴露指标给 Prometheus 监控
rabbitmq_auth_backend_ldap 支持 LDAP 鉴权
rabbitmq_web_mqtt 支持 MQTT 协议通过 WebSocket 接入

举例

复制代码
# ✅ 1. 启用 MQTT 插件

 rabbitmq-plugins enable rabbitmq_mqtt

 ps: 默认 MQTT 插件监听在端口:1883

# ✅ 2. 修改配置文件(rabbitmq.conf)

 配置文件路径取决于安装方式,常见于 /etc/rabbitmq/rabbitmq.conf

 添加以下内容:
  mqtt.allow_anonymous = true
  mqtt.default_user = mqtt
  mqtt.default_pass = mqtt
  mqtt.vhost = /
  mqtt.exchange = amq.topic

# ✅ 3. 添加对应的 RabbitMQ 用户(和权限)

 # 添加用户
 rabbitmqctl add_user mqtt mqtt

 # 设置用户权限(允许操作默认 vhost)
 rabbitmqctl set_permissions -p / mqtt ".*" ".*" ".*"

 ps: ⚠️ 如果你没创建这个用户,匿名连接时会用默认用户登录,但 RabbitMQ 查不到,会连接失败!

# 连接验证(例如使用 MQTT.fx)

 • 主机地址:localhost 或服务器地址
 • 端口:1883
 • 协议版本:MQTT 3.1 或 3.1.1
 • 用户名密码留空
 • 连接即可成功

AMQP,STOMP,MQTT 协议

复制代码
# AMQP(Advanced Message Queuing Protocol)

 • 全称:Advanced Message Queuing Protocol(高级消息队列协议)
 • 设计目标:企业级消息中间件标准协议
 • 主要支持者:RabbitMQ、Apache Qpid、ActiveMQ、Azure Service Bus

 • 企业系统间可靠通信(例如银行系统、ERP)
 • 电商订单、交易等需要"确保投递"的系统

# STOMP(Simple Text Oriented Messaging Protocol)

 • 全称:Simple (or Streaming) Text Oriented Messaging Protocol
 • 目标:简化消息系统通信,让客户端更容易接入
 • 语法:类 HTTP 协议格式,是基于文本的协议

 • 聊天室、在线客服、实时通知系统
 • 前后端推送消息(如 Spring WebSocket + STOMP)

# MQTT(Message Queuing Telemetry Transport)

 • 设计者:IBM
 • 目标:为物联网(IoT)设计的超轻量级协议
 • 传输层:基于 TCP/IP,支持 TLS 加密

 • 智能家居、智能表计、工业物联网(工业 4.0)
 • ESP32、树莓派、Arduino 等设备通信
特性 AMQP STOMP MQTT
传输层 TCP TCP / WebSocket TCP
消息模型 队列+交换机 目的地(destination) 发布/订阅(topic)
数据格式 二进制 文本 二进制(紧凑)
路由功能 强(支持多种交换机) 弱(只有 destination) 无交换机,使用主题匹配
支持离线传输 支持(通过持久化) 一般 强(QoS 机制)
面向对象 后端系统(可靠性优先) 前端浏览器或轻量消息传输 物联网设备,嵌入式系统
是否适合硬件设备 ✅ 是
是否适合浏览器 否(不直接支持) ✅ 是(配合 WebSocket) 否(需额外桥接)
RabbitMQ 原生支持 ✅ 是 插件支持 插件支持

RabbitMQ 如何支持这些协议?

协议 插件 默认端口 说明
AMQP 原生支持 5672 全功能
STOMP rabbitmq_stomp 61613 文本协议支持
STOMP + Web rabbitmq_web_stomp 15674 浏览器连接
MQTT rabbitmq_mqtt 1883 IoT 设备连接
MQTT + Web rabbitmq_web_mqtt 15675 浏览器用 MQTT

总结

RabbitMQ 与同类产品对比

特性 / 中间件 RabbitMQ Kafka RocketMQ ActiveMQ Redis Stream
协议支持 AMQP、MQTT、STOMP、HTTP 自定义协议 自定义 JMS Redis 协议
消息模型 基于队列和交换机(多种路由) 基于 Topic 分区 Topic+Tag Topic+Queue 基于流结构(Stream)
消息顺序 同一个队列内有序 同一个分区内严格有序 同分区内顺序 顺序控制弱 保证插入顺序
吞吐量 中等(万级) 极高(百万级) 较低 中等偏高
可靠性 高(持久化+ACK) 非常高(副本机制) 一般(依赖配置) 高(AOF 持久化)
消息延迟 极低 较低 较高
消息堆积能力 中(基于内存+磁盘) 极强(磁盘存储) 一般 一般(依赖内存)
使用复杂度 中(配置灵活) 高(需要理解架构) 中偏高 简单 简单
部署运维 简单(Erlang) 复杂(需 ZooKeeper/KRaft) 中等(Java) 简单 非常简单
语言支持 多语言(官方/社区) 多语言(强大生态) 多语言 Java为主 所有支持 Redis 的语言
事务消息 支持(幂等控制) 支持事务消息 支持但复杂 不支持
消息过期/延迟 支持 TTL/延迟队列 需外部组件 支持 支持 支持(Stream 的 ID 控制)
死信队列支持 ✅ 支持 ❌ 不原生支持 ✅ 支持 ✅ 支持 ❌ 不原生支持
场景适用度 后端解耦、异步任务、IoT 大数据日志、实时计算、流处理 金融、交易系统、事务消息 简单异步、老项目 简单队列/流计算/缓存场景

适用场景对比分析

场景类型 推荐中间件 理由说明
Web 系统异步任务、接口解耦 RabbitMQ / ActiveMQ 多语言支持好,消息路由灵活,易上手
高吞吐、日志收集、大数据流 Kafka 极高性能,支持海量堆积,分布式处理能力强
事务性强的系统(订单/支付) RocketMQ 原生支持事务消息,可靠性高
IoT 设备通信 RabbitMQ(MQTT 插件) 支持 MQTT 协议,兼容多种设备
浏览器实时通信(推送) RabbitMQ(Web STOMP)、Socket.IO STOMP 插件适合前端
简单异步任务、小队列应用 Redis Stream 上手快、无需额外组件,轻量级
多租户 SaaS 系统 RabbitMQ / Kafka RabbitMQ 多 vhost 隔离强,Kafka 多 topic 隔离也可

参考资料

rabbitmq: https://www.rabbitmq.com/

rabbitmq下载: https://www.rabbitmq.com/docs/download

源码: https://github.com/rabbitmq/rabbitmq-server