很多人刚开始用 RabbitMQ 时,觉得它就是一个"生产者发消息、消费者收消息"的工具。
但其实,RabbitMQ 的真正强大之处,在于它能通过不同的 交换机类型 和 绑定规则,灵活支持多种通信方式。
比如:
- 想让多个服务同时收到同一条通知?可以用 广播模式(Fanout)。
- 想按消息类型分别处理日志?可以用 路由模式(Direct)。
- 想监听所有订单相关的事件?主题模式(Topic) 就很合适。
这些不同的用法,被总结为 RabbitMQ 的六大经典工作模式。
掌握它们,你就能根据业务需求,设计出更合理、更高效的消息架构。
下面我们通过一个完整的SpringBoot项目和示例来做一个全面的了解。让你看得懂、跑得通、也能用得上!
项目结构建议(便于组织)
lua
src/main/java/com/example/rabbitdemo/
├── config/ -- 配置类
│ ├── SimpleConfig.java
│ ├── WorkQueueConfig.java
│ ├── FanoutConfig.java
│ ├── DirectConfig.java
│ ├── TopicConfig.java
│ └── RpcConfig.java
├── producer/ --生产者
│ ├── SimpleProducer.java
│ ├── WorkProducer.java
│ ├── FanoutProducer.java
│ ├── DirectProducer.java
│ ├── TopicProducer.java
│ └── RpcClient.java
├── consumer/ -- 消费者
│ ├── SimpleConsumer.java
│ ├── WorkConsumer1.java
│ ├── WorkConsumer2.java
│ ├── FanoutConsumerA.java
│ ├── FanoutConsumerB.java
│ ├── DirectErrorConsumer.java
│ ├── DirectInfoConsumer.java
│ ├── TopicOrderConsumer.java
│ ├── TopicLogConsumer.java
│ └── RpcServer.java
├── controller/
│ ├── TestController.java // 聚合所有测试接口
└── RabbitDemoApplication.java
1. 启动类(RabbitDemoApplication.java)
java
package com.example.rabbitdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RabbitDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RabbitDemoApplication.class, args);
}
}
这是标准 Spring Boot 启动类,无需额外配置。
Maven 依赖(pom.xml)------完整版
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>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>rabbit-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rabbit-demo</name>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置文件(application.yml)
yaml
server:
port: 8080
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
listener:
simple:
# 手动 ACK 示例(工作队列中用到)
acknowledge-mode: auto # 默认 auto,如需手动改为 manual
prefetch: 1 # 配合 manual 使用,一次只取1条
六大模式完整实现
一、简单模式(Simple)
一个生产者 → 一个队列 → 一个消费者
config/SimpleConfig.java(配置类)
java
package com.example.rabbitdemo.config;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SimpleConfig {
public static final String SIMPLE_QUEUE = "simple.queue";
// 创建队列
@Bean
public Queue simpleQueue() {
// 参数:队列名,是否持久化(true=重启后保留),是否排他,是否自动删除
return new Queue(SIMPLE_QUEUE, true, false, false);
}
}
@Configuration:标记类为配置类,Spring在启动时会处理其中的Bean定义@Bean:声明方法返回的对象应该被注册为Spring应用上下文中的Bean
producer/SimpleProducer.java(生产者)
java
package com.example.rabbitdemo.producer;
import com.example.rabbitdemo.config.SimpleConfig;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SimpleProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(String message) {
// 发送到默认交换机,routingKey 为队列名
rabbitTemplate.convertAndSend(SimpleConfig.SIMPLE_QUEUE, message);
}
}
consumer/SimpleConsumer.java(消费者)
java
package com.example.rabbitdemo.consumer;
import com.example.rabbitdemo.config.SimpleConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class SimpleConsumer {
@RabbitListener(queues = SimpleConfig.SIMPLE_QUEUE)
public void receive(String message) {
System.out.println("【简单模式】收到消息: " + message);
}
}
适用场景
- 最基础的异步任务,比如发送欢迎邮件。
二、工作队列模式(Work Queue)
- 一个队列,多个消费者竞争消费(默认轮询)
- 适用于任务分发、耗时任务异步处理
注意:SpringBoot 默认是自动 ACK,建议改为手动 ACK 防止消息丢失。
config/WorkQueueConfig.java(配置类)
java
package com.example.rabbitdemo.config;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WorkQueueConfig {
public static final String WORK_QUEUE = "work.queue";
// 创建队列
@Bean
public Queue workQueue() {
return new Queue(WORK_QUEUE, true);
}
}
producer/WorkProducer.java(生产者)
java
package com.example.rabbitdemo.producer;
import com.example.rabbitdemo.config.WorkQueueConfig;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class WorkProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(String message) {
rabbitTemplate.convertAndSend(WorkQueueConfig.WORK_QUEUE, message);
}
}
consumer/WorkConsumer1.java(消费者1)
java
package com.example.rabbitdemo.consumer;
import com.example.rabbitdemo.config.WorkQueueConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class WorkConsumer1 {
@RabbitListener(queues = WorkQueueConfig.WORK_QUEUE)
public void receive(String message) throws InterruptedException {
System.out.println("【Worker1】处理任务: " + message);
Thread.sleep(1000); // 模拟耗时
}
}
consumer/WorkConsumer2.java(消费者2)
java
package com.example.rabbitdemo.consumer;
import com.example.rabbitdemo.config.WorkQueueConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class WorkConsumer2 {
@RabbitListener(queues = WorkQueueConfig.WORK_QUEUE)
public void receive(String message) throws InterruptedException {
System.out.println("【Worker2】处理任务: " + message);
Thread.sleep(1000);
}
}
工作队列特点
- 多个消费者共享同一个队列
- RabbitMQ使用轮询方式分发消息
- 每个消息只被一个消费者处理
- 适合任务分发和负载均衡
三、发布/订阅模式(Fanout)
- 一个生产者 → Fanout 交换机 → 多个队列 → 多个消费者(广播)
- 所有绑定到该交换机的队列都会收到消息
config/FanoutConfig.java(配置类)
java
package com.example.rabbitdemo.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FanoutConfig {
public static final String FANOUT_EXCHANGE = "fanout.exchange";
public static final String FANOUT_QUEUE_A = "fanout.queue.a";
public static final String FANOUT_QUEUE_B = "fanout.queue.b";
/**
* 这里创建的是Fanout类型的交换器
* Fanout特点:广播模式,消息会发送到所有绑定的队列
*/
@Bean
public FanoutExchange fanoutExchange() {
return new FanoutExchange(FANOUT_EXCHANGE);
}
// 创建队列A
@Bean
public Queue fanoutQueueA() {
return new Queue(FANOUT_QUEUE_A);
}
// 创建队列B
@Bean
public Queue fanoutQueueB() {
return new Queue(FANOUT_QUEUE_B);
}
/**
* 将队列A绑定到交换器
* 绑定后,发送到fanout.exchange的消息都会进入队列A
*/
@Bean
public Binding bindingA() {
return BindingBuilder.bind(fanoutQueueA()).to(fanoutExchange());
}
/**
* 将队列B绑定到交换器
* 绑定后,发送到fanout.exchange的消息都会进入队列B
*/
@Bean
public Binding bindingB() {
return BindingBuilder.bind(fanoutQueueB()).to(fanoutExchange());
}
}
工作流程示意图
css
生产者发送消息到交换器
↓
[fanout.exchange] ← 广播交换器
↓ ↓
队列A收到消息 队列B收到消息
↓ ↓
消费者A处理 消费者B处理
producer/FanoutProducer.java(生产者)
java
package com.example.rabbitdemo.producer;
import com.example.rabbitdemo.config.FanoutConfig;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class FanoutProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(String message) {
// Fanout 交换机忽略 routingKey,所以传空字符串
rabbitTemplate.convertAndSend(FanoutConfig.FANOUT_EXCHANGE, "", message);
}
}
consumer/FanoutConsumerA.java(消费者A)
java
package com.example.rabbitdemo.consumer;
import com.example.rabbitdemo.config.FanoutConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class FanoutConsumerA {
@RabbitListener(queues = FanoutConfig.FANOUT_QUEUE_A)
public void receive(String message) {
System.out.println("【Fanout A】收到广播: " + message);
}
}
consumer/FanoutConsumerB.java(消费者B)
java
package com.example.rabbitdemo.consumer;
import com.example.rabbitdemo.config.FanoutConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class FanoutConsumerB {
@RabbitListener(queues = FanoutConfig.FANOUT_QUEUE_B)
public void receive(String message) {
System.out.println("【Fanout B】收到广播: " + message);
}
}
FanoutExchange 特点
- 广播机制:消息发送到所有绑定的队列
- 忽略routingKey:无论routingKey是什么,所有队列都会收到消息
- 一对多通信:适合消息广播场景
当你调用生产者时,消费者A和B都会同时收到消息。
适用场景:群发通知,比如用户注册后同时发邮件、短信、站内信。
四、路由模式(Direct)
根据 routing key 精确匹配路由到指定队列
config/DirectConfig.java(配置类)
java
package com.example.rabbitdemo.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DirectConfig {
public static final String DIRECT_EXCHANGE = "direct.exchange";
public static final String DIRECT_QUEUE_ERROR = "direct.queue.error";
public static final String DIRECT_QUEUE_INFO = "direct.queue.info";
// 创建Direct类型的交换器
@Bean
public DirectExchange directExchange() {
return new DirectExchange(DIRECT_EXCHANGE);
}
// 创建错误日志队列
@Bean
public Queue errorQueue() {
return new Queue(DIRECT_QUEUE_ERROR);
}
// 创建信息日志队列
@Bean
public Queue infoQueue() {
return new Queue(DIRECT_QUEUE_INFO);
}
/**
* 关键绑定:错误队列 ←[routingKey="error"]--- 交换器
* 含义:只有routingKey为"error"的消息才会进入错误队列
*/
@Bean
public Binding errorBinding() {
// 绑定:队列 ←[routingKey="error"]--- 交换机
return BindingBuilder.bind(errorQueue()).to(directExchange()).with("error");
}
/**
* 绑定:信息队列 ←[routingKey="info"]--- 交换器
* 含义:只有routingKey为"info"的消息才会进入信息队列
*/
@Bean
public Binding infoBinding() {
return BindingBuilder.bind(infoQueue()).to(directExchange()).with("info");
}
}
绑定关系示意图:
ini
direct.exchange(交换器)
↓
|-- routingKey="error" → direct.queue.error(错误队列)
|-- routingKey="info" → direct.queue.info(信息队列)
producer/DirectProducer.java(生产者)
java
package com.example.rabbitdemo.producer;
import com.example.rabbitdemo.config.DirectConfig;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DirectProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(String routingKey, String message) {
rabbitTemplate.convertAndSend(DirectConfig.DIRECT_EXCHANGE, routingKey, message);
}
}
consumer/DirectErrorConsumer.java(消费者)
java
package com.example.rabbitdemo.consumer;
import com.example.rabbitdemo.config.DirectConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class DirectErrorConsumer {
@RabbitListener(queues = DirectConfig.DIRECT_QUEUE_ERROR)
public void receive(String message) {
System.out.println("【ERROR】日志: " + message);
}
}
consumer/DirectInfoConsumer.java(消费者)
java
package com.example.rabbitdemo.consumer;
import com.example.rabbitdemo.config.DirectConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class DirectInfoConsumer {
@RabbitListener(queues = DirectConfig.DIRECT_QUEUE_INFO)
public void receive(String message) {
System.out.println("【INFO】日志: " + message);
}
}
测试场景
场景1:发送错误日志
java
// 调用:POST /send-log?level=error&content=数据库连接失败
directProducer.send("error", "[error] 数据库连接失败");
// 输出结果:
// 【ERROR】日志: [error] 数据库连接失败
// (只有错误消费者收到,信息消费者收不到)
场景2:发送信息日志
java
// 调用:POST /send-log?level=info&content=用户登录成功
directProducer.send("info", "[info] 用户登录成功");
// 输出结果:
// 【INFO】日志: [info] 用户登录成功
// (只有信息消费者收到,错误消费者收不到)
场景3:发送不存在的路由键
java
// 调用:POST /send-log?level=warning&content=系统警告
directProducer.send("warning", "[warning] 系统警告");
// 输出结果:
// (两个消费者都收不到,因为warning路由键没有队列绑定)
DirectExchange 特点
- 精确匹配:routingKey必须完全匹配绑定键
- 选择性路由:消息只发送到匹配的队列
- 多重绑定:多个队列可以使用相同的binding key
不同级别的日志由不同的消费者处理,实现责任分离
适用场景:按类型处理消息,比如 error 日志进监控队列,info 日志进归档队列。
五、通配符模式(Topic主题模式)
使用通配符(*匹配一个词,#匹配零个或多个词)进行模糊路由
例如: order.*= 所有以 order.开头的消息 *.error.#= 所有包含 .error.的消息(任意位置)
config/TopicConfig.java(配置类)
java
package com.example.rabbitdemo.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TopicConfig {
public static final String TOPIC_EXCHANGE = "topic.exchange";
public static final String TOPIC_QUEUE_ORDER = "topic.queue.order";
public static final String TOPIC_QUEUE_LOG = "topic.queue.log";
// 创建Topic类型的交换器(支持通配符)
@Bean
public TopicExchange topicExchange() {
return new TopicExchange(TOPIC_EXCHANGE);
}
// 订单队列
@Bean
public Queue orderQueue() {
return new Queue(TOPIC_QUEUE_ORDER);
}
// 日志队列
@Bean
public Queue logQueue() {
return new Queue(TOPIC_QUEUE_LOG);
}
// 监听 order 开头的消息,如 order.created, order.cancelled
@Bean
public Binding orderBinding() {
return BindingBuilder.bind(orderQueue()).to(topicExchange()).with("order.*");
}
// 监听包含 error 的日志,如 user.error.login, db.error.timeout
@Bean
public Binding logBinding() {
return BindingBuilder.bind(logQueue()).to(topicExchange()).with("*.error.#");
}
}
绑定关系示意图:
ini
topic.exchange(主题交换器)
↓
|-- routingKey="order.*" → topic.queue.order(订单队列)
|-- routingKey="*.error.#" → topic.queue.log(日志队列)
producer/TopicProducer.java(生产者)
java
package com.example.rabbitdemo.producer;
import com.example.rabbitdemo.config.TopicConfig;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TopicProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送消息到主题交换器
* @param routingKey 路由键(支持通配符匹配)
* @param message 消息内容
*/
public void send(String routingKey, String message) {
rabbitTemplate.convertAndSend(TopicConfig.TOPIC_EXCHANGE, routingKey, message);
}
}
consumer/TopicOrderConsumer.java(Order消费者)
java
package com.example.rabbitdemo.consumer;
import com.example.rabbitdemo.config.TopicConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class TopicOrderConsumer {
@RabbitListener(queues = TopicConfig.TOPIC_QUEUE_ORDER)
public void receive(String message) {
System.out.println("【订单服务】收到: " + message);
}
}
consumer/TopicLogConsumer.java(Log消费者)
java
package com.example.rabbitdemo.consumer;
import com.example.rabbitdemo.config.TopicConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class TopicLogConsumer {
@RabbitListener(queues = TopicConfig.TOPIC_QUEUE_LOG)
public void receive(String message) {
System.out.println("【日志服务】收到错误: " + message);
}
}
测试
java
// 发送:order.created 路由键的消息
topicProducer.send("order.created", "用户123创建了新订单");
// 发送:user.error.login 路由键的消息
topicProducer.send("user.error.login", "用户登录失败,密码错误");
TopicExchange 通配符规则
星号 (*) 通配符
- 匹配恰好一个单词
- 示例:
order.*匹配:order.create✓order.pay✓order.cancel✓order.detail.view✗(两个点,多个单词)
井号 (#) 通配符
- 匹配零个或多个单词
- 示例:
*.error.#匹配:system.error✓db.error.timeout✓user.error.login.failed✓error✗(缺少前面的单词)
适用场景:灵活的消息分类,比如监听所有订单相关事件。
六、RPC 模式(Request/Reply)
- 客户端发送请求,服务端处理并返回结果(类似远程调用)
- 利用 replyTo 和 correlationId 实现请求-响应匹配
config/RpcConfig.java(配置类)
java
package com.example.rabbitdemo.config;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RpcConfig {
public static final String RPC_QUEUE = "rpc.queue";
@Bean
public Queue rpcQueue() {
// RPC 队列通常不需要持久化,因为请求是临时的
return new Queue(RPC_QUEUE, false, false, true);
}
}
producer/RpcClient.java(客户端)
java
package com.example.rabbitdemo.producer;
import com.example.rabbitdemo.config.RpcConfig;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RpcClient {
@Autowired
private RabbitTemplate rabbitTemplate;
public String call(String message) {
// convertSendAndReceive 是同步阻塞调用,会等待回复
return (String) rabbitTemplate.convertSendAndReceive(RpcConfig.RPC_QUEUE, message);
}
}
consumer/RpcServer.java(服务端)
java
package com.example.rabbitdemo.consumer;
import com.example.rabbitdemo.config.RpcConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class RpcServer {
@RabbitListener(queues = RpcConfig.RPC_QUEUE)
public String handle(String request) {
System.out.println("【RPC 服务端】处理请求: " + request);
// 返回值会被 Spring 自动发回客户端的 replyTo 队列
return "【响应】" + request.toUpperCase();
}
}
RPC队列参数特点
- durable: false:RPC通常是临时请求,不需要持久化
- exclusive: false:允许多个客户端连接
- autoDelete: true:没有消费者时自动删除,适合临时通信
RPC通信机制
- 客户端发送请求到RPC队列
- 服务端从队列获取请求并处理
- 服务端将响应发送到客户端指定的回复队列
- 客户端从回复队列获取响应
适用场景:需要获取处理结果的异步调用(较少用,一般用 HTTP 或 gRPC 更直接)。
测试控制器
controller/TestController.java(所以模式的接口测试)
java
package com.example.rabbitdemo.controller;
import com.example.rabbitdemo.producer.*;
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 TestController {
@Autowired
private SimpleProducer simpleProducer;
@Autowired
private WorkProducer workProducer;
@Autowired
private FanoutProducer fanoutProducer;
@Autowired
private DirectProducer directProducer;
@Autowired
private TopicProducer topicProducer;
@Autowired
private RpcClient rpcClient;
@GetMapping("/simple")
public String simple() {
simpleProducer.send("Hello Simple");
return "Simple message sent";
}
@GetMapping("/work/{msg}")
public String work(@PathVariable String msg) {
workProducer.send(msg);
return "Work task sent: " + msg;
}
@GetMapping("/fanout")
public String fanout() {
fanoutProducer.send("Broadcast!");
return "Fanout message sent";
}
@GetMapping("/direct/{key}/{msg}")
public String direct(@PathVariable String key, @PathVariable String msg) {
directProducer.send(key, msg);
return "Direct message sent to [" + key + "]";
}
@GetMapping("/topic/{key}/{msg}")
public String topic(@PathVariable String key, @PathVariable String msg) {
topicProducer.send(key, msg);
return "Topic message sent with key: " + key;
}
@GetMapping("/rpc/{msg}")
public String rpc(@PathVariable String msg) {
String result = rpcClient.call(msg);
return "RPC Result: " + result;
}
}
访问测试?
启动应用后,依次访问:
http://localhost:8080/simplehttp://localhost:8080/work/task1http://localhost:8080/fanouthttp://localhost:8080/direct/error/系统错误http://localhost:8080/direct/info/用户登录http://localhost:8080/topic/order.created/新订单http://localhost:8080/topic/db.error.timeout/数据库超时http://localhost:8080/rpc/hello
观察控制台输出即可验证每种模式。
总结
通过以上六个模块的完整实现,我们系统性地覆盖了 RabbitMQ 的核心工作模式:
| 模式 | 核心特点 | 典型场景 |
|---|---|---|
| 简单模式 | 1:1 队列通信 | 基础异步任务(如邮件发送) |
| 工作队列 | 多消费者竞争消费 | 负载均衡、耗时任务分发 |
| 发布/订阅(Fanout) | 广播到所有绑定队列 | 群发通知、多系统同步 |
| 路由模式(Direct) | 精确匹配 routing key | 日志分级、类型过滤 |
| 主题模式(Topic) | 通配符模糊匹配 | 事件总线、灵活订阅 |
| RPC 模式 | 请求-响应式通信 | 同步结果获取(较少用但重要) |
关键理解:RabbitMQ 的强大,不在于队列,而在于交换机 + 绑定 + 路由这一整套消息路由机制。合理选择 Exchange 类型和 Binding 策略,才能让消息精准抵达目的地。
本文首发于公众号:程序员刘大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!
📌往期精彩
《async/await 到底要不要加 try-catch?异步错误处理最佳实践》
《Vue3 和 Vue2 的核心区别?很多开发者都没完全搞懂的 10 个细节》