基于 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 配置如下:

<!-- 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 连接信息(与文档中一致):
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 重启后队列不丢失):
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 队列:
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(消息发送模板)@Autowiredprivate RabbitTemplate rabbitTemplate;/*** 下单接口:模拟用户下单,发送消息到物流系统*/@RequestMapping("/createOrder")public String createOrder() {// 1. 模拟下单逻辑(实际场景需包含参数校验、数据库操作等)String orderId = UUID.randomUUID().toString(); // 生成唯一订单IDString 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,避免与订单系统冲突):
server:port: 9090 # 物流系统端口(与订单系统不同)spring:rabbitmq:# 与订单系统一致的 RabbitMQ 连接信息addresses: amqp://study:study@110.41.51.65:15673/bite
4.2 编写消息监听逻辑
通过 @RabbitListener 注解声明监听 order.create 队列,接收消息后模拟发货处理:
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 启动服务
- 先启动物流系统(确保消费者已监听队列,避免消息丢失);
- 再启动订单系统(生产者就绪,可发送消息)。
5.2 触发下单与消息发送
通过浏览器或 Postman 访问订单系统的下单接口:
- 接口地址:
http://127.0.0.1:8080/order/createOrder - 接口返回:
下单成功!订单ID:xxx-xxx-xxx-xxx(xxx 为 UUID 生成的唯一ID)
5.3 观察日志验证通信结果
- 订单系统日志:打印
订单系统:下单成功,订单ID:xxx-xxx-xxx-xxx,表示消息已发送; - 物流系统日志:打印
物流系统:下单成功,订单ID:xxx-xxx-xxx-xxx,开始安排发货...,表示消息已接收并处理; - RabbitMQ 管理界面验证:
- 访问 RabbitMQ 管理界面(
http://110.41.51.65:15672),切换到bite虚拟主机; - 点击
Queues标签,找到order.create队列,Ready列显示0(消息已被消费),Consumers列显示1(物流系统已监听)。
- 访问 RabbitMQ 管理界面(
六、进阶:发送对象类型消息(非字符串)
实际场景中,应用间常需传递复杂数据(如订单详情对象),需配置 JSON 序列化器,确保对象能在不同应用间正确传输。
6.1 配置 JSON 消息序列化器
在订单系统和物流系统中,均添加消息转换器配置(使用 Jackson2JsonMessageConverter):
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 序列化)@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate template = new RabbitTemplate(connectionFactory);template.setMessageConverter(new Jackson2JsonMessageConverter());return template;}// 配置消费者的消息转换器(确保能正确反序列化对象)@Beanpublic SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();factory.setConnectionFactory(connectionFactory);factory.setMessageConverter(new Jackson2JsonMessageConverter());return factory;}
}
6.2 定义订单对象
在两个应用中创建相同的 OrderInfo 实体类(包路径需一致,确保反序列化成功):
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;// Lombok 注解:自动生成 getter/setter、构造方法(需引入 lombok 依赖)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderInfo {private String orderId; // 订单IDprivate String productName;// 商品名称private Long totalPrice; // 订单总价
}
若未使用 Lombok,需手动编写 getter、setter 和构造方法。
6.3 修改消息发送与接收逻辑
订单系统(生产者):发送 OrderInfo 对象
@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 对象
// 监听 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,物流系统日志会打印订单对象的详细信息,表明对象消息已正确传输。
七、注意事项
- 端口冲突:两个应用需使用不同端口(如订单 8080、物流 9090),避免启动失败;
- 队列一致性:生产者声明的队列名(
order.create)需与消费者监听的队列名完全一致,否则消息无法路由; - 消息可靠性:
- 队列需配置
durable=true(持久化),避免 RabbitMQ 重启后队列丢失; - 若需确保消息不丢失,可开启“发布确认模式”(参考文档中 Publisher Confirms 模式)和“消费者手动确认”;
- 队列需配置
- 对象序列化:跨应用传递对象时,需确保两个应用的实体类包路径、字段名、类型完全一致,并配置统一的序列化器(如 JSON);
- 虚拟主机隔离:文档中使用
bite虚拟主机,实际场景中不同业务线应使用独立虚拟主机,通过virtual-host配置实现资源隔离。
