一、为什么要学 RabbitMQ?
RabbitMQ 是分布式项目常用消息中间件,核心解决“同步调用”痛点,通俗说就是解耦、削峰、异步,先懂作用再学整合,更易理解。
1.1 核心作用
•业务解耦:下单后无需同步调用支付、库存等服务,发送消息异步处理,避免一个服务故障导致全流程崩溃;
•流量削峰:秒杀等高并发场景,请求先进入队列,服务器按能力逐步消费,防止过载;
•异步处理:发送短信、日志等无需用户等待的操作,异步执行提升体验;
•分布式事务最终一致性:跨服务操作通过消息确认,确保数据一致(入门暂不深入)。
1.2 典型应用场景
•电商场景:下单→支付→库存→物流→短信,全流程异步解耦;
•日志场景:异步收集日志,避免阻塞业务;
•通知场景:注册、订单变更等短信/邮件异步发送;
•高并发场景:秒杀请求缓冲,防止服务器宕机。
1.3 核心组件
消息流转:生产者 → 交换机 → 队列 → 消费者,各组件作用如下:
•生产者:发送消息的一方(如下单服务);
•消费者:接收并处理消息的一方(如短信服务);
•队列:存储消息,先进先出,消费后删除;
•交换机:消息分发中心,按规则将消息转发到队列(核心);
•路由键:生产者携带的消息标识,用于交换机分发;
•绑定:关联交换机和队列,设置路由规则;
•虚拟主机:隔离消息资源,入门用默认“/”即可。
二、环境准备
推荐 Docker 安装(一键启动),无 Docker 环境可选择本地安装,步骤简洁可落地。
2.1 Docker 一键安装
前提:已安装 Docker,执行以下命令启动 RabbitMQ(含管理后台):
# 拉取镜像(带管理后台) docker pull rabbitmq:3-management # 启动容器,设置账号密码 docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123456 --restart=always rabbitmq:3-management验证:访问 http://localhost:15672,用 admin/123456 登录,能进入即成功。
2.2 本地安装(无 Docker)
RabbitMQ 依赖 Erlang,步骤如下(Windows 为例):
1.安装 Erlang:
• 下载:https://www.erlang.org/downloads(推荐 25.x 版本,与 RabbitMQ 兼容);
• 安装后配置环境变量 ERlang_HOME(安装路径),Path 添加 %ERLANG_HOME%\bin;
• cmd 输入
erl -version,显示版本即成功。
2.安装 RabbitMQ:
• 下载:https://www.rabbitmq.com/download.html(Windows 版本);
• 安装后,cmd 进入 sbin 目录,执行
rabbitmq-plugins enable rabbitmq_management(启用后台);• 执行
rabbitmq-service start启动服务,访问 http://localhost:15672,用 guest/guest 登录。
常见问题:guest 登录失败?在
rabbitmq.conf添加loopback_users = none,重启服务即可。2.3 Maven 依赖
SpringBoot 一键整合,
pom.xml添加以下依赖:<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <relativePath/> </parent> <groupId>com.example</groupId> <artifactId>springboot-rabbitmq-intro</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- Web 依赖,用于测试接口 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- RabbitMQ 核心依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <!-- Lombok 简化代码(可选) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> </project>三、SpringBoot 基础配置
application.yml配置 RabbitMQ 连接信息,注释详细,直接复制:spring: rabbitmq: host: localhost # 服务地址,服务器填IP port: 5672 # 消息通信端口 username: admin # Docker账号,本地默认guest password: 123456 # Docker密码,本地默认guest virtual-host: / # 默认虚拟主机 listener: simple: acknowledge-mode: auto # 自动确认消息,简化操作 concurrency: 1 # 消费者并发数,入门设1 publisher-confirm-type: none # 关闭生产者确认,入门简化 publisher-returns: false # 关闭消息返回,入门简化四、模式一:Direct 直连交换机
核心:一对一精准匹配,路由键与绑定键完全一致,消息才会分发到对应队列,适合点对点通信(如下单消息)。
4.1 配置类(队列+交换机+绑定)
import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class DirectConfig { // 声明队列(持久化,重启不丢失) @Bean public Queue directQueue() { return QueueBuilder.durable("direct.queue").autoDelete(false).exclusive(false).build(); } // 声明直连交换机 @Bean public DirectExchange directExchange() { return DirectExchange.directExchange("direct.exchange").durable(true).autoDelete(false).build(); } // 绑定,路由键 direct.key @Bean public Binding directBinding(Queue directQueue, DirectExchange directExchange) { return BindingBuilder.bind(directQueue).to(directExchange).with("direct.key"); } }4.2 生产者(发送消息)
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class DirectProducer { @Autowired private RabbitTemplate rabbitTemplate; // 测试接口:http://localhost:8080/send/direct/消息内容 @GetMapping("/send/direct/{msg}") public String sendDirect(@PathVariable String msg) { String message = "【Direct消息】" + msg; rabbitTemplate.convertAndSend("direct.exchange", "direct.key", message); return "发送成功:" + message; } }4.3 消费者(监听消息)
import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component // 必须交给Spring管理 public class DirectConsumer { @RabbitListener(queues = "direct.queue") // 监听指定队列 public void consumeDirect(String msg) { System.out.println("Direct消费者接收:" + msg); } }4.4 测试步骤
1. 启动 RabbitMQ 和 SpringBoot 项目;
2. 访问接口
http://localhost:8080/send/direct/HelloRabbitMQ;3. 查看 IDEA 控制台,消费者输出消息即成功。
4.5 避坑要点
• 路由键与绑定键必须完全一致,否则消息丢失;
• 队列/交换机需设为持久化,重启 RabbitMQ 不丢失;
• 消费者需加
@Component注解,否则无法监听。
五、模式二:Fanout 扇出交换机(广播模式)
核心:一对多广播,无需路由键,消息会广播到所有绑定的队列,适合系统公告、活动通知等场景。
5.1 配置类(多队列+交换机+绑定)
import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FanoutConfig { // 声明两个队列,接收广播消息 @Bean public Queue fanoutQueue1() { return QueueBuilder.durable("fanout.queue1").build(); } @Bean public Queue fanoutQueue2() { return QueueBuilder.durable("fanout.queue2").build(); } // 声明扇出交换机 @Bean public FanoutExchange fanoutExchange() { return FanoutExchange.fanoutExchange("fanout.exchange").durable(true).build(); } // 两个队列都绑定到交换机(无需路由键) @Bean public Binding fanoutBinding1(Queue fanoutQueue1, FanoutExchange fanoutExchange) { return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange); } @Bean public Binding fanoutBinding2(Queue fanoutQueue2, FanoutExchange fanoutExchange) { return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange); } }5.2 生产者(发送广播消息)
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class FanoutProducer { @Autowired private RabbitTemplate rabbitTemplate; // 测试接口:http://localhost:8080/send/fanout/消息内容 @GetMapping("/send/fanout/{msg}") public String sendFanout(@PathVariable String msg) { String message = "【Fanout广播消息】" + msg; rabbitTemplate.convertAndSend("fanout.exchange", "", message); // 路由键填空 return "广播发送成功:" + message; } }5.3 消费者(多消费者监听)
import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component public class FanoutConsumer { @RabbitListener(queues = "fanout.queue1") public void consumeFanout1(String msg) { System.out.println("Fanout消费者1接收:" + msg); } @RabbitListener(queues = "fanout.queue2") public void consumeFanout2(String msg) { System.out.println("Fanout消费者2接收:" + msg); } }5.4 测试与避坑
测试:访问接口后,两个消费者都会接收消息;
避坑:扇出交换机无需路由键,填写也会被忽略,绑定即接收。六、模式三:Topic 主题交换机
核心:模糊匹配路由键,通过通配符实现多对多路由,适合复杂场景(如按模块分发消息)。
6.1 通配符规则
•
#:匹配1个或多个单词(如order.#匹配order.create、order.pay.success);•
*:匹配1个单词(如order.*匹配order.create,不匹配order.pay.success)。
6.2 配置类(模糊绑定)
import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class TopicConfig { // 3个队列,不同绑定键 @Bean public Queue topicQueue1() { return QueueBuilder.durable("topic.queue1").build(); } // order.# @Bean public Queue topicQueue2() { return QueueBuilder.durable("topic.queue2").build(); } // order.pay.* @Bean public Queue topicQueue3() { return QueueBuilder.durable("topic.queue3").build(); } // *.login // 主题交换机 @Bean public TopicExchange topicExchange() { return TopicExchange.topicExchange("topic.exchange").durable(true).build(); } // 绑定不同规则 @Bean public Binding topicBinding1(Queue topicQueue1, TopicExchange topicExchange) { return BindingBuilder.bind(topicQueue1).to(topicExchange).with("order.#"); } @Bean public Binding topicBinding2(Queue topicQueue2, TopicExchange topicExchange) { return BindingBuilder.bind(topicQueue2).to(topicExchange).with("order.pay.*"); } @Bean public Binding topicBinding3(Queue topicQueue3, TopicExchange topicExchange) { return BindingBuilder.bind(topicQueue3).to(topicExchange).with("*.login"); } }6.3 生产者(不同路由键消息)
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TopicProducer { @Autowired private RabbitTemplate rabbitTemplate; // 测试1:order.create(匹配queue1) @GetMapping("/send/topic/order/create") public String sendTopic1() { String msg = "订单创建:10001"; rabbitTemplate.convertAndSend("topic.exchange", "order.create", msg); return "发送成功:" + msg; } // 测试2:order.pay.success(匹配queue1、queue2) @GetMapping("/send/topic/order/pay/success") public String sendTopic2() { String msg = "订单支付:10001,99元"; rabbitTemplate.convertAndSend("topic.exchange", "order.pay.success", msg); return "发送成功:" + msg; } // 测试3:user.login(匹配queue3) @GetMapping("/send/topic/user/login") public String sendTopic3() { String msg = "用户登录:admin"; rabbitTemplate.convertAndSend("topic.exchange", "user.login", msg); return "发送成功:" + msg; } }6.4 消费者与测试
import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component public class TopicConsumer { @RabbitListener(queues = "topic.queue1") public void consumeTopic1(String msg) { System.out.println("Topic消费者1(order.#):" + msg); } @RabbitListener(queues = "topic.queue2") public void consumeTopic2(String msg) { System.out.println("Topic消费者2(order.pay.*):" + msg); } @RabbitListener(queues = "topic.queue3") public void consumeTopic3(String msg) { System.out.println("Topic消费者3(*.login):" + msg); } }测试:依次访问3个接口,控制台输出与预期匹配即成功;
避坑:路由键需用点分隔,否则通配符无效,无匹配队列则消息丢失。七、3种交换机对比与选型
交换机类型
核心特点
路由规则
适用场景
Direct(直连) 一对一,精准路由
路由键与绑定键完全一致
点对点通信(下单、个人通知)
Fanout(扇出) 一对多,广播
无需路由键,广播到所有绑定队列
系统公告、活动通知
Topic(主题) 多对多,模糊匹配
通过 #、* 通配符匹配
复杂路由(按模块分发消息)
八、常见问题与解决方案(避坑指南)
1.消息发送成功,消费者收不到?
• 原因:绑定关系错误、消费者无 @Component、队列未持久化;
• 解决方案:检查绑定、添加注解、重启服务。
2.管理后台登录失败?
• 原因:账号密码错误、guest 未开启远程登录;
• 解决方案:核对账号,添加
loopback_users = none并重启。
3.项目启动报错:无法连接 RabbitMQ?
• 原因:RabbitMQ 未启动、配置错误、端口未开放;
• 解决方案:启动 RabbitMQ、核对配置、开放 5672/15672 端口。
学习本就是一个长期积累的过程,没有捷径,唯有坚持。希望这些干货能够真正帮到你,学以致用,不断提升,在自己的领域里越走越远。喜欢本文,别忘了点赞、在看、转发,我们下期干货继续!