基于 Spring Boot + RabbitMQ 实现应用通信

一、应用通信架构设计

1.1 需求场景

用户在订单系统 完成下单后,订单系统无需直接调用物流系统接口,而是通过 RabbitMQ 发送"下单成功"消息;物流系统监听 RabbitMQ 队列,接收消息后触发发货流程,实现"订单-物流"两个独立应用的异步通信。

1.2 架构图

  • 角色划分:订单系统作为生产者,负责发送消息;物流系统作为消费者,负责接收并处理消息;
  • 核心组件 :使用 RabbitMQ 的简单队列(order.create)实现消息传递,队列持久化确保消息不丢失;
  • 解耦优势:订单系统与物流系统无需感知对方地址,只需通过 RabbitMQ 交互,减少系统耦合。

二、前置准备:环境与依赖

2.1 环境要求

  • JDK 8+(文档中推荐版本,兼容性稳定);
  • Spring Boot 2.7.x 或 3.x(本文以 2.7.10 为例);
  • RabbitMQ 服务(文档中使用云服务器部署,地址 110.41.51.65:15673,虚拟主机 bite,用户 study/study)。

2.2 依赖引入

两个应用(订单系统、物流系统)均需引入 Spring Boot RabbitMQ 依赖和 Web 依赖(订单系统需提供下单接口),pom.xml 配置如下:

xml 复制代码
<!-- Spring Boot RabbitMQ 整合依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- Web 依赖:订单系统用于提供下单接口 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 测试依赖(可选) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

三、步骤1:搭建订单系统(生产者)

订单系统的核心功能是"处理下单逻辑"并"发送消息到 RabbitMQ",需完成配置、队列声明、接口编写三个核心步骤。

3.1 配置 RabbitMQ 连接

src/main/resources/application.yml 中配置 RabbitMQ 连接信息(与文档中一致):

yaml 复制代码
server:
  port: 8080  # 订单系统端口(避免与物流系统冲突)

spring:
  rabbitmq:
    # 连接地址:amqp://用户名:密码@IP:端口/虚拟主机
    addresses: amqp://study:study@110.41.51.65:5672/bite
    # 可选:单独配置参数(与addresses二选一)
    # host: 110.41.51.65
    # port: 5672
    # username: study
    # password: study
    # virtual-host: bite

3.2 声明通信队列

通过 @Configuration 类声明持久化队列 order.create(确保 RabbitMQ 重启后队列不丢失):

java 复制代码
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {
    // 声明订单-物流通信队列(durable=true:持久化)
    @Bean("orderQueue")
    public Queue orderQueue() {
        return QueueBuilder.durable("order.create").build();
    }
}

3.3 编写下单接口与消息发送逻辑

创建 OrderController,提供下单接口,下单成功后通过 RabbitTemplate 发送消息到 order.create 队列:

java 复制代码
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;

@RestController
@RequestMapping("/order")
public class OrderController {
    // 注入 Spring 自动创建的 RabbitTemplate(消息发送模板)
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 下单接口:模拟用户下单,发送消息到物流系统
     */
    @RequestMapping("/createOrder")
    public String createOrder() {
        // 1. 模拟下单逻辑(实际场景需包含参数校验、数据库操作等)
        String orderId = UUID.randomUUID().toString(); // 生成唯一订单ID
        String orderMsg = "下单成功,订单ID:" + orderId;
        System.out.println("订单系统:" + orderMsg);

        // 2. 发送消息到 RabbitMQ 的 order.create 队列
        // 参数1:交换机(默认交换机,空字符串)
        // 参数2:路由键(队列名,与声明的队列一致)
        // 参数3:消息内容
        rabbitTemplate.convertAndSend("", "order.create", orderMsg);

        return "下单成功!订单ID:" + orderId;
    }
}

四、步骤2:搭建物流系统(消费者)

物流系统的核心功能是"监听 RabbitMQ 队列",接收订单系统发送的消息并触发发货逻辑,只需完成配置和监听逻辑编写。

4.1 配置 RabbitMQ 连接

物流系统需与订单系统连接到同一 RabbitMQ 服务,application.yml 配置如下(端口设为 9090,避免与订单系统冲突):

yaml 复制代码
server:
  port: 9090  # 物流系统端口(与订单系统不同)

spring:
  rabbitmq:
    # 与订单系统一致的 RabbitMQ 连接信息
    addresses: amqp://study:study@110.41.51.65:15673/bite

4.2 编写消息监听逻辑

通过 @RabbitListener 注解声明监听 order.create 队列,接收消息后模拟发货处理:

java 复制代码
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class OrderMessageListener {
    /**
     * 监听 order.create 队列,接收订单消息并处理发货
     * @param message 订单系统发送的消息内容
     */
    @RabbitListener(queues = "order.create") // 直接指定监听的队列名
    public void handleOrderMessage(String message) {
        // 模拟物流系统处理逻辑:接收消息、解析订单信息、调用发货接口等
        System.out.println("物流系统:" + message + ",开始安排发货...");
        // 实际场景需添加:订单信息解析、调用物流API、更新发货状态等代码
    }
}
  • @RabbitListener 是 Spring AMQP 核心注解,无需手动创建连接或通道,Spring 会自动管理监听逻辑;
  • 方法参数 String message 直接接收消息内容(Spring 自动完成消息反序列化),也可使用 Message 类型获取消息属性(如消息ID、路由键等)。

五、步骤3:运行验证应用通信

5.1 启动服务

  1. 先启动物流系统(确保消费者已监听队列,避免消息丢失);
  2. 再启动订单系统(生产者就绪,可发送消息)。

5.2 触发下单与消息发送

通过浏览器或 Postman 访问订单系统的下单接口:

  • 接口地址:http://127.0.0.1:8080/order/createOrder
  • 接口返回:下单成功!订单ID:xxx-xxx-xxx-xxx(xxx 为 UUID 生成的唯一ID)

5.3 观察日志验证通信结果

  1. 订单系统日志 :打印 订单系统:下单成功,订单ID:xxx-xxx-xxx-xxx,表示消息已发送;
  2. 物流系统日志 :打印 物流系统:下单成功,订单ID:xxx-xxx-xxx-xxx,开始安排发货...,表示消息已接收并处理;
  3. RabbitMQ 管理界面验证
    • 访问 RabbitMQ 管理界面(http://110.41.51.65:15672),切换到 bite 虚拟主机;
    • 点击 Queues 标签,找到 order.create 队列,Ready 列显示 0(消息已被消费),Consumers 列显示 1(物流系统已监听)。

六、进阶:发送对象类型消息(非字符串)

实际场景中,应用间常需传递复杂数据(如订单详情对象),需配置 JSON 序列化器,确保对象能在不同应用间正确传输。

6.1 配置 JSON 消息序列化器

在订单系统和物流系统中,均添加消息转换器配置(使用 Jackson2JsonMessageConverter):

java 复制代码
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQMessageConfig {
    // 配置 RabbitTemplate 的消息转换器(JSON 序列化)
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        template.setMessageConverter(new Jackson2JsonMessageConverter());
        return template;
    }

    // 配置消费者的消息转换器(确保能正确反序列化对象)
    @Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        return factory;
    }
}

6.2 定义订单对象

在两个应用中创建相同的 OrderInfo 实体类(包路径需一致,确保反序列化成功):

java 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

// Lombok 注解:自动生成 getter/setter、构造方法(需引入 lombok 依赖)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderInfo {
    private String orderId;    // 订单ID
    private String productName;// 商品名称
    private Long totalPrice;   // 订单总价
}

若未使用 Lombok,需手动编写 getter、setter 和构造方法。

6.3 修改消息发送与接收逻辑

订单系统(生产者):发送 OrderInfo 对象
java 复制代码
@RequestMapping("/createOrderWithObject")
public String createOrderWithObject() {
    // 1. 构建订单对象
    String orderId = UUID.randomUUID().toString();
    OrderInfo orderInfo = new OrderInfo(orderId, "手机", 5999L);
    System.out.println("订单系统:发送订单对象," + orderInfo);

    // 2. 发送对象消息(RabbitTemplate 自动序列化为 JSON)
    rabbitTemplate.convertAndSend("", "order.create", orderInfo);

    return "下单成功!订单详情:" + orderInfo;
}
物流系统(消费者):接收 OrderInfo 对象
java 复制代码
// 监听 order.create 队列,直接接收 OrderInfo 对象
@RabbitListener(queues = "order.create")
public void handleOrderObjectMessage(OrderInfo orderInfo) {
    System.out.println("物流系统:接收订单对象,开始发货...");
    System.out.println("订单ID:" + orderInfo.getOrderId());
    System.out.println("商品名称:" + orderInfo.getProductName());
    System.out.println("订单总价:" + orderInfo.getTotalPrice());
}

6.4 验证对象消息通信

访问订单系统接口 http://127.0.0.1:8080/order/createOrderWithObject,物流系统日志会打印订单对象的详细信息,表明对象消息已正确传输。

七、注意事项

  1. 端口冲突:两个应用需使用不同端口(如订单 8080、物流 9090),避免启动失败;
  2. 队列一致性 :生产者声明的队列名(order.create)需与消费者监听的队列名完全一致,否则消息无法路由;
  3. 消息可靠性
    • 队列需配置 durable=true(持久化),避免 RabbitMQ 重启后队列丢失;
    • 若需确保消息不丢失,可开启"发布确认模式"(参考文档中 Publisher Confirms 模式)和"消费者手动确认";
  4. 对象序列化 :跨应用传递对象时,需确保两个应用的实体类包路径、字段名、类型完全一致,并配置统一的序列化器(如 JSON);
  5. 虚拟主机隔离 :文档中使用 bite 虚拟主机,实际场景中不同业务线应使用独立虚拟主机,通过 virtual-host 配置实现资源隔离。
相关推荐
小范同学_3 小时前
Spring集成WebSocket
java·spring boot·websocket·spring·1024程序员节
进击的圆儿3 小时前
网络编程实战02·从零搭建Epoll服务器
1024程序员节
计算衎3 小时前
Jenkins上实现CI集成软件信息Teams群通知案例实现。
python·jenkins·1024程序员节·microsoft azure·teams消息群通知·微软 graph api
爱看老照片3 小时前
计算机端口
1024程序员节
go_bai3 小时前
Linux_基础IO(2)
linux·开发语言·经验分享·笔记·学习方法·1024程序员节
西部森林牧歌3 小时前
拒绝笨重,一款轻量、极致简洁的开源CI/CD工具 - Arbess
1024程序员节·cicd·tiklab·arbess
浆果02073 小时前
【图像超分】论文复现:轻量化超分 | RLFN的Pytorch源码复现,跑通源码,整合到EDSR-PyTorch中进行训练、测试
人工智能·python·深度学习·超分辨率重建·1024程序员节
Arnold.Shen4 小时前
Vcenter7使用主机配置文件重置ESXI主机 root 密码
1024程序员节
ai_moe4 小时前
MapAnything: 通用前馈式度量3D重建
1024程序员节