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