Lecture03-RabbitMQ-SpringBoot整合

文章目录

    [toc]

    单词词性音标含义
    startern./ˈstɑːtə(r)/启动器(SpringBoot 场景依赖包)
    templaten./ˈtemplɪt/模板(RabbitTemplate,发送消息的对象)
    listenern./ˈlɪsənə(r)/监听器(监听队列接收消息)
    bindingn./ˈbaɪndɪŋ/绑定(交换机和队列的对应关系)
    quorumn./ˈkwɔːrəm/仲裁(Quorum 队列,4 生产推荐的高可用队列)
    durableadj./ˈdjʊərəbl/持久化的(重启不丢失)

    Lecture03-RabbitMQ-SpringBoot整合

    环境:Spring Boot 3.x + spring-boot-starter-amqp + RabbitMQ 4(Docker 方式,见《RabbitMQ4-Ubuntu22.04-安装与操作清单》) 目标:生产者发消息、消费者收消息;交换机 / 队列 / 绑定关系用两种方式实现 全程只讲用法。前置:RabbitMQ 4 已用 Docker 跑起来,管理台账号 admin / admin123(第 3 步设的)。


    1、前置:添加依赖 + 连接配置

    ① pom.xml 加依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.0.0</version>   <!-- 以当前稳定 4.x 为准 -->
        <relativePath/>
    </parent>
    
    <properties>
        <java.version>17</java.version>   <!-- SpringBoot4 基线 Java 17+ -->
    </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-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    

    ② application.yml 配置连接

    spring:
      rabbitmq:
        host: localhost          # Docker 在本地则 localhost,远程服务器填 IP
        port: 5672
        username: admin          # 第 3 步创建容器时设的用户
        password: admin123
        virtual-host: /          # 默认虚拟主机
    

    说明:连接参数和你 docker run 设的 RABBITMQ_DEFAULT_USER / PASS 一致。连不上先查 host/port/账号。


    2、交换机、队列、绑定的两种创建方式

    目标:消息 发到交换机 → 按路由键 → 进入队列 → 被消费者取走。交换机、队列、绑定关系(exchange + routing key + queue)是整套前提。

    1、方式一:手动在 Management UI 创建(SpringBoot 代码最简)

    ① 在 UI 上建好(参考《安装与操作清单》第 4 步)

    • 交换机:demo.exchange(type=direct,Durable)
    • 队列:demo.queue(Durable)
    • 绑定:从 demo.exchange → demo.queue,Routing key = demo.routing

    ② SpringBoot 这边代码很简——不用声明任何 @Bean,因为交换机和队列已经在 UI 里建好了,代码只负责收发:

    // 生产者
    @RestController
    public class ProducerController {
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        @GetMapping("/send")
        public String send() {
            rabbitTemplate.convertAndSend("demo.exchange", "demo.routing", "Hello RabbitMQ 4 !");
            return "已发送";
        }
    }
    
    // 消费者
    @Component
    public class DemoConsumer {
        @RabbitListener(queues = "demo.queue")   // 只监听队列名,其余 UI 已建好
        public void onMessage(String message) {
            System.out.println("收到消息:" + message);
        }
    }
    
    • 特点:代码最少;前提是队列 / 交换机已手动建好,否则启动时 @RabbitListener 找不到队列会报错。

    2、方式二:SpringBoot 配置 + 启动时自动创建

    ① 写一个配置类,用 @Bean 声明交换机、队列、绑定——SpringBoot 启动时会自动在 RabbitMQ 里创建(若不存在):

    @Configuration
    public class RabbitConfig {
        public static final String EXCHANGE = "demo2.exchange";
        public static final String QUEUE   = "demo2.queue";
        public static final String ROUTING = "demo2.routing";
    
        // 交换机(direct,持久化)
        @Bean
        public DirectExchange exchange() {
            return new DirectExchange(EXCHANGE, true, false);
        }
    
        // 队列(经典队列,持久化)
        @Bean
        public Queue queue() {
            return QueueBuilder.durable(QUEUE).build();
            // RabbitMQ 4 生产建议用 Quorum 队列(单节点即可测试,副本=1;集群才有复制/高可用):
            //   return QueueBuilder.durable(QUEUE).quorum().build();
        }
    
        // 绑定:queue 绑到 exchange,路由键 ROUTING
        @Bean
        public Binding binding() {
            return BindingBuilder.bind(queue()).to(exchange()).with(ROUTING);
        }
    }
    

    ② 生产者和消费者代码不变(把队列名换成常量 QUEUE 即可):

    @RabbitListener(queues = RabbitConfig.QUEUE)   // 消费者
    
    rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE, RabbitConfig.ROUTING, "Hello ...");
    
    • 特点:配置即代码,启动自动建,无需手动 UI;缺点是结构写在代码里、改结构要改代码重启。

    3、两种方式对比

    维度方式一:UI 手动创建方式二:代码自动创建
    交换机/队列来源Management UI 手动建SpringBoot 启动时 @Bean 自动建
    SpringBoot 代码最简(只写收发)需 @Configuration 声明 3 个 @Bean
    结构谁说了算运维手动维护随代码走
    适用场景生产、结构固定学习、开发期图省事

    3、生产者发送消息

    核心方法:RabbitTemplate.convertAndSend(交换机, 路由键, 消息)

    // 字符串
    rabbitTemplate.convertAndSend(EXCHANGE, ROUTING, "Hello RabbitMQ 4 !");
    
    // 对象(自动序列化为 JSON)
    rabbitTemplate.convertAndSend(EXCHANGE, ROUTING, new Order(1, "鲜花"));
    
    // 什么都不传 = 发到默认交换机(按队列名直接路由)
    rabbitTemplate.convertAndSend("demo.queue", "直接发到队列");
    

    验证发送成功:

    • 浏览器调 http://localhost:8080/send
    • 到 Management UI → Queues → demo.queue → Get messages 能看到消息;或看控制台消费者打印

    关键点:发送时给的路由键必须和绑定时一致,否则消息进不了队列(发到交换机但路由不到任何队列,消息丢失)。


    4、消费者接收消息

    核心注解:@RabbitListener(queues = "队列名")

    @Component
    public class Consumer {
        @RabbitListener(queues = "demo.queue")
        public void onMessage(String message) {
            System.out.println("收到:" + message);
        }
    }
    

    5、验证流程 + 常见问题

    跑通顺序

    1. RabbitMQ 容器已 Up(docker ps)
    2. SpringBoot 启动无报错(方式二会自动建交换机/队列/绑定)
    3. 调 /send 接口发消息
    4. 消费者控制台打印出消息,或 UI 队列里看到消息 ✅

    常见问题速查

    现象可能原因处理
    连接失败host/port/账号不对对照 yml 和 docker run 设的用户密码;guest 已被删,别用 guest
    启动报"队列不存在"方式一没在 UI 建队列先到 UI 建 demo.queue;或改用方式二自动建
    消息发不出去、队列没有路由键和绑定不一致检查发送的 ROUTING 与绑定的 routing key 是否一致
    消费者收不到监听队列名写错核对 @RabbitListener(queues=...) 与实际队列名
    想用 Quorum 队列4 生产建议QueueBuilder.durable(QUEUE).quorum().build()

    6、本教程用到的核心类速查

    东西角色
    RabbitTemplate.convertAndSend(交换机, 路由键, 消息)生产者发送
    @RabbitListener(queues = "队列名")消费者监听
    @Bean Queue / DirectExchange / Binding + BindingBuilder方式二:代码自动创建
    spring-boot-starter-amqpSpring 对 RabbitMQ 的封装依赖

    7、本节验证

    • 会加依赖并配置连接 ✅
    • 会用两种方式创建交换机/队列/绑定(UI 手动 vs 代码自动)✅
    • 会用 RabbitTemplate 发送消息 ✅
    • 会用 @RabbitListener 接收消息并跑通验证 ✅
    end