RabbitMQ 的 6 种工作模式你都掌握了吗?附完整可运行代码

很多人刚开始用 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通信机制

  1. 客户端发送请求到RPC队列
  2. 服务端从队列获取请求并处理
  3. 服务端将响应发送到客户端指定的回复队列
  4. 客户端从回复队列获取响应

适用场景:需要获取处理结果的异步调用(较少用,一般用 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/simple
  • http://localhost:8080/work/task1
  • http://localhost:8080/fanout
  • http://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 个细节》

《Java 开发必看:什么时候用 for,什么时候用 Stream?》

《这 10 个 MySQL 高级用法,让你的代码又快又好看》

相关推荐
archko1 小时前
用rust写了一个桌面app,就不再想用kmp了
开发语言·后端·rust
星释1 小时前
Rust 练习册 109:深入探索列表关系判断
开发语言·后端·rust
古城小栈1 小时前
Spring AI Alibaba 重磅更新:Java 的开发新纪元
java·人工智能·spring
老华带你飞1 小时前
作业管理|基于Java作业管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot·后端
JIngJaneIL1 小时前
基于Java人力资源管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot
星释1 小时前
Rust 练习册 110:探索倍数之和的数学之美
开发语言·后端·rust
pengzhuofan1 小时前
用AI武装你的学习:高效掌握Java新技术的方法论
java·人工智能·学习
fanruitian2 小时前
springboot-mybatisplus-demo
spring boot·后端·mybatis·mybatisplus
明月惊雀2 小时前
微服务依赖版本管理
java·数据库·微服务