RocketMQ在Spring Cloud上的基础使用
一、整合前置说明
Spring Cloud 整合 RocketMQ 是基于 RocketMQ Spring Boot Starter 扩展,结合 Spring Cloud 生态特性(如配置中心、服务发现、链路追踪)实现云原生、可配置、易扩展的消息通信。
1. 环境依赖
| 组件 | 版本 | 说明 |
|---|
| Spring Cloud | 2022.0.x(Kilburn)/ Hoxton.SR12 | 适配 Spring Boot 版本 |
| Spring Boot | 2.7.x / 3.1.x | 与 Spring Cloud 版本匹配 |
| RocketMQ Spring Boot Starter | 2.2.3 / 2.3.0 | 4.x 用 2.2.3,5.x 用 2.3.0+ |
| RocketMQ | 4.9.7 / 5.1.4 | 服务端版本需与 Starter 兼容 |
2. Maven 核心依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
<version>2022.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2022.0.0.0-RC2</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-spring-cloud-mvc</artifactId>
<version>8.16.0</version>
</dependency>
二、核心配置
1. 配置中心统一管理(以 Nacos 为例)
1.1 Nacos 配置文件(rocketmq-config.yaml)
rocketmq:
name-server: ${ROCKETMQ_NAMESRV:127.0.0.1:9876}
producer:
group: ${spring.application.name}-producer
send-message-timeout: 5000
retry-times-when-send-failed: 3
max-message-size: 4194304
consumer:
group: ${spring.application.name}-consumer
consume-thread-min: 10
consume-thread-max: 30
max-reconsume-times: 3
consume-message-batch-max-size: 10
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
import:
- nacos:rocketmq-config.yaml?group=DEFAULT_GROUP&refresh=true
1.2 应用本地配置(bootstrap.yml)
spring:
application:
name: rocketmq-cloud-demo
profiles:
active: dev
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
refresh-enabled: true
2. 核心配置项增强说明(Spring Cloud 特性)
| 配置项 | Spring Cloud 增强点 | 生产价值 |
|---|
rocketmq.name-server | 支持环境变量/配置中心动态注入 | 不同环境(dev/test/prod)无需改代码 |
producer.group | 基于 ${spring.application.name} 自动生成 | 微服务分组规范,避免手动命名冲突 |
config.refresh-enabled | 支持 RocketMQ 配置动态刷新 | 无需重启服务即可调整重试次数、线程数等 |
三、各消息类型代码示例
1. 普通消息(微服务解耦场景)
1.1 生产者(微服务业务层)
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@RefreshScope
public class OrderNormalProducer {
@Resource
private RocketMQTemplate rocketMQTemplate;
public void sendOrderCreateMsg(String orderId, String productId, Integer count) {
OrderMsgDTO msgDTO = OrderMsgDTO.builder()
.orderId(orderId)
.productId(productId)
.count(count)
.build();
Message<OrderMsgDTO> message = MessageBuilder
.withPayload(msgDTO)
.setHeader(RocketMQHeaders.KEYS, orderId)
.setHeader(RocketMQHeaders.TAGS, "order_create")
.setHeader("X-SERVICE-NAME", "order-service")
.build();
rocketMQTemplate.syncSend("order_topic:order_create", message);
System.out.println("[订单服务] 发送普通消息:" + orderId);
}
@lombok.Data
@lombok.Builder
public static class OrderMsgDTO {
private String orderId;
private String productId;
private Integer count;
}
}
1.2 消费者(库存服务)
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.MessageModel;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@Component
@RefreshScope
@RocketMQMessageListener(
consumerGroup = "${spring.application.name}-consumer", // 基于服务名自动生成
topic = "order_topic",
selectorExpression = "order_create",
messageModel = MessageModel.CLUSTERING,
consumeMode = ConsumeMode.CONCURRENTLY,
maxReconsumeTimes = "${rocketmq.consumer.max-reconsume-times}" // 配置中心注入
)
public class StockNormalConsumer implements RocketMQListener<OrderNormalProducer.OrderMsgDTO> {
@Override
public void onMessage(OrderNormalProducer.OrderMsgDTO msg) {
System.out.println("[库存服务] 收到订单创建消息:" + msg);
}
}
2. 顺序消息(微服务有序业务)
2.1 生产者(物流服务)
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@RefreshScope
public class LogisticsOrderedProducer {
@Resource
private RocketMQTemplate rocketMQTemplate;
public void sendLogisticsStatusMsg(String orderId, String status) {
LogisticsMsgDTO msgDTO = LogisticsMsgDTO.builder()
.orderId(orderId)
.status(status)
.build();
rocketMQTemplate.syncSendOrderly(
"logistics_topic:logistics_status",
MessageBuilder.withPayload(msgDTO).build(),
orderId
);
System.out.println("[物流服务] 发送顺序消息:" + orderId + "-" + status);
}
@lombok.Data
@lombok.Builder
public static class LogisticsMsgDTO {
private String orderId;
private String status;
}
}
2.2 消费者(订单状态同步服务)
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@Component
@RefreshScope
@RocketMQMessageListener(
consumerGroup = "${spring.application.name}-consumer",
topic = "logistics_topic",
selectorExpression = "logistics_status",
consumeMode = ConsumeMode.ORDERLY // 强制顺序消费
)
public class OrderStatusOrderedConsumer implements RocketMQListener<LogisticsOrderedProducer.LogisticsMsgDTO> {
@Override
public void onMessage(LogisticsOrderedProducer.LogisticsMsgDTO msg) {
System.out.println("[订单服务] 收到物流顺序消息:" + msg);
}
}
3. 延迟消息(微服务定时任务)
3.1 生产者(订单超时取消)
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@RefreshScope
public class OrderDelayProducer {
@Resource
private RocketMQTemplate rocketMQTemplate;
public void sendOrderTimeoutMsg(String orderId) {
Message rocketMsg = new Message(
"order_delay_topic",
"order_timeout",
orderId.getBytes()
);
int delayLevel = Integer.parseInt(System.getProperty("rocketmq.delay.level", "15"));
rocketMsg.setDelayTimeLevel(delayLevel);
rocketMQTemplate.getProducer().send(rocketMsg);
System.out.println("[订单服务] 发送延迟消息:" + orderId + "(延迟等级" + delayLevel + ")");
}
}
3.2 消费者(订单超时处理)
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@Component
@RefreshScope
@RocketMQMessageListener(
consumerGroup = "${spring.application.name}-consumer",
topic = "order_delay_topic",
selectorExpression = "order_timeout"
)
public class OrderDelayConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String orderId) {
System.out.println("[订单服务] 处理超时订单:" + orderId);
}
}
4. 事务消息(微服务分布式事务)
4.1 事务监听器(核心)
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
@RefreshScope
@RocketMQTransactionListener(txProducerGroup = "${spring.application.name}-tx-producer")
@Component
public class PayTransactionListener implements RocketMQLocalTransactionListener {
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
String orderId = msg.getHeaders().get("KEYS").toString();
try {
boolean paySuccess = payService.deductBalance(orderId);
boolean recordSuccess = payRecordService.createRecord(orderId);
if (paySuccess && recordSuccess) {
return RocketMQLocalTransactionState.COMMIT;
} else {
return RocketMQLocalTransactionState.ROLLBACK;
}
} catch (Exception e) {
return RocketMQLocalTransactionState.UNKNOWN;
}
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
String orderId = msg.getHeaders().get("KEYS").toString();
boolean isSuccess = payRecordService.queryPayStatus(orderId);
return isSuccess ? RocketMQLocalTransactionState.COMMIT : RocketMQLocalTransactionState.ROLLBACK;
}
@Resource
private PayService payService;
@Resource
private PayRecordService payRecordService;
}
4.2 事务生产者(支付服务)
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@RefreshScope
public class PayTransactionProducer {
@Resource
private RocketMQTemplate rocketMQTemplate;
public void sendPaySuccessMsg(String orderId, Double payAmount) {
PayMsgDTO msgDTO = PayMsgDTO.builder()
.orderId(orderId)
.payAmount(payAmount)
.build();
Message<PayMsgDTO> message = MessageBuilder
.withPayload(msgDTO)
.setHeader("KEYS", orderId)
.setHeader("TAGS", "pay_success")
.build();
rocketMQTemplate.sendMessageInTransaction(
"pay_topic:pay_success",
message,
null
);
System.out.println("[支付服务] 发送事务消息(半消息):" + orderId);
}
@lombok.Data
@lombok.Builder
public static class PayMsgDTO {
private String orderId;
private Double payAmount;
}
}
5. 批量消息(微服务批量处理)
5.1 生产者(日志收集服务)
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Component
@RefreshScope
public class LogBatchProducer {
@Resource
private RocketMQTemplate rocketMQTemplate;
public void sendLogBatchMsg(List<LogDTO> logList) {
List<Message> msgList = new ArrayList<>();
for (LogDTO log : logList) {
Message msg = new Message(
"log_topic",
"service_log",
log.getLogId().getBytes(),
log.toString().getBytes()
);
msgList.add(msg);
}
rocketMQTemplate.getProducer().send(msgList);
System.out.println("[日志服务] 发送批量日志消息:" + logList.size() + "条");
}
@lombok.Data
public static class LogDTO {
private String logId;
private String serviceName;
private String content;
private Long timestamp;
}
}
5.2 批量消费者(日志分析服务)
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQBatchListener;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@RefreshScope
@RocketMQMessageListener(
consumerGroup = "${spring.application.name}-consumer",
topic = "log_topic",
selectorExpression = "service_log",
consumeMessageBatchMaxSize = "${rocketmq.consumer.consume-message-batch-max-size}"
)
public class LogBatchConsumer implements RocketMQBatchListener<String> {
@Override
public void onMessage(List<String> msgs) {
System.out.println("[日志分析服务] 收到批量日志:" + msgs.size() + "条");
}
}
四、Spring Cloud 整合 RocketMQ 的优缺点
优点(核心价值)
| 优势 | 详细说明 | 微服务场景价值 |
|---|
| 配置统一管理 | 结合 Nacos/Apollo 配置中心,实现 RocketMQ 配置动态注入、刷新 | 不同环境(dev/test/prod)无需改代码,配置可灰度发布 |
| 微服务解耦 | 替代 RPC 直连,通过消息实现微服务异步通信,降低服务依赖 | 订单、库存、支付服务解耦,单个服务故障不影响整体 |
| 服务治理整合 | 可结合 Spring Cloud 链路追踪(SkyWalking)、监控(Prometheus) | 全链路追踪消息收发,监控消息堆积、消费延迟 |
| 动态扩缩容 | 消费者组支持微服务实例动态扩缩容,自动负载均衡 | 秒杀场景可快速扩容消费者实例,应对流量峰值 |
| 命名规范统一 | 基于 ${spring.application.name} 自动生成生产者/消费者组名 | 避免人工命名冲突,符合微服务命名规范 |
| 配置动态刷新 | 通过 @RefreshScope 实现 RocketMQ 配置热更新 | 无需重启服务即可调整重试次数、线程数等参数 |
| 分布式事务适配 | 事务消息结合微服务本地事务,实现最终一致性 | 解决支付、订单等场景的分布式事务问题 |
缺点(注意事项)
| 问题 | 详细说明 | 解决方案 |
|---|
| 依赖复杂度提升 | 引入 Spring Cloud + RocketMQ 双重依赖,版本兼容问题突出 | 严格按照版本适配表选择依赖,避免跨版本使用 |
| 运维成本增加 | 需同时维护 RocketMQ 集群 + Spring Cloud 配置中心/注册中心 | 标准化部署流程,统一监控 RocketMQ 和微服务 |
| 配置优先级问题 | Spring Cloud 配置中心、本地配置、环境变量优先级易混乱 | 明确配置优先级(配置中心 > 环境变量 > 本地配置) |
| 链路追踪复杂 | 消息跨微服务传递时,链路追踪需手动传递 Header | 使用 RocketMQ Headers 传递 traceId,集成 SkyWalking |
| 动态配置风险 | 错误的动态配置(如重试次数改为0)可能导致业务异常 | 配置修改前做灰度验证,增加配置校验规则 |
| 消费堆积排查难 | 微服务集群下,消费堆积需定位到具体实例 | 结合 RocketMQ Dashboard + 微服务监控,定位堆积实例 |
| 事务回查复杂度 | 微服务事务回查需提供跨服务查询接口,增加开发成本 | 封装通用事务回查组件,统一回查逻辑 |
五、生产级最佳实践
1. 配置管理
- 所有 RocketMQ 配置放入配置中心,避免硬编码;
- 配置按环境分组(dev/test/prod),通过
spring.profiles.active 切换;
- 关键配置(如
max-reconsume-times)增加修改审批流程。
2. 链路追踪
- 在消息 Header 中传递
traceId/spanId,集成 SkyWalking/Zipkin;
- 日志中打印
msgKey + traceId,便于问题定位。
3. 监控告警
- 监控指标:消息堆积量、发送/消费失败率、延迟时间、选举次数(Dledger);
- 告警规则:堆积量 > 10000 触发告警,消费失败率 > 1% 触发告警。
4. 幂等性保障
- 所有消费端基于
msgKey 做幂等(Redis 分布式锁/数据库唯一键);
- 避免因重试导致重复处理业务。
5. 故障演练
- 定期演练 Leader 宕机、网络分区、消费堆积等场景;
- 验证 Spring Cloud 配置动态刷新、微服务扩缩容的有效性。
总结
核心关键点
- 整合核心:Spring Cloud 整合 RocketMQ 本质是「RocketMQ Spring Boot Starter + 微服务生态增强」,核心价值是配置统一管理、服务解耦、动态扩缩容;
- 优缺点平衡:优势在于微服务解耦和配置灵活性,缺点是依赖复杂度和运维成本增加,需通过标准化流程规避;
- 消息类型适配:
- 普通消息:微服务异步解耦首选;
- 顺序消息:物流、订单状态同步等有序业务;
- 延迟消息:订单超时、定时任务等场景;
- 事务消息:支付、库存等分布式事务场景;
- 批量消息:日志收集、数据同步等吞吐敏感场景;
- 生产准则:配置统一管理、链路全追踪、消费必幂等、监控全覆盖。