RocketMQ从实战到源码:SpringBoot整合RocketMQ
😄生命不息,写作不止
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🏆 博客首页 @怒放吧德德 To记录领地 @一个有梦有戏的人
🌝分享学习心得,欢迎指正,大家一起学习成长!
转发请携带作者信息 @怒放吧德德(掘金) @一个有梦有戏的人(CSDN)
前言
在微服务架构中,消息中间件是实现服务解耦、削峰填谷、异步通信的核心组件,而 RocketMQ 作为阿里开源的高性能、高可靠分布式消息中间件,凭借高吞吐量、低延迟、强一致性等特性,广泛应用于各类分布式系统。SpringBoot 则以“约定大于配置”的理念,极大简化了第三方组件的整合成本。本文将从实操角度出发,详细讲解 RocketMQ 与 SpringBoot 的完整整合流程,包含环境准备、依赖配置、生产者/消费者实现、测试验证,以及常见问题排查,适合新手快速上手,也可作为开发参考手册。
1 整合 SpringBoot
1.1 环境
rocketmq: 2.2.3 RocketMQ 与 SpringBoot 的整合依赖官方提供的 starter 组件,版本适配至关重要,否则会出现自动配置失效、Bean 注入失败等问题。本文选用业内稳定兼容版本组合(新手直接照搬即可),版本对应关系参考 Apache RocketMQ 官方兼容性矩阵:
- JDK:17(需要 1.8+,RocketMQ 对 JDK 11+ 兼容性一般,生产环境优先选用 JDK 8,避免踩坑)
- SpringBoot:2.7.x(稳定版,避免使用 3.x 版本,与 RocketMQ starter 存在兼容断点)
- RocketMQ:4.9.7(稳定版,社区长期维护,适配 SpringBoot 2.7.x)
- RocketMQ SpringBoot Starter:2.2.3(如果使用 2.3 的版本,jdk 需要 17,并且 springboot 需要 3.0 以上)
- Maven:3.6+(项目构建工具)
1.2 引入依赖
创建 SpringBoot 项目,引入 RocketMQ 整合依赖,核心是 RocketMQ 官方提供的 spring-boot-starter,无需手动引入原生 RocketMQ 客户端依赖,starter 会自动完成依赖管理和自动配置。
<!-- RocketMQ 依赖 -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.3</version>
</dependency>
1.3 配置
# rocketmq 配置项,对应 RocketMQProperties 配置类
rocketmq:
name-server: 192.168.109.134:9876 # RocketMQ Namesrv
# Producer 配置项 (只有配置了生产者,才会初始化RocketMQTemplate)
producer:
group: demo-spring-group # 生产者分组(自定义)
send-message-timeout: 3000 # 发送消息超时时间,单位:毫秒。默认为 3000 。
compress-message-body-threshold: 4096 # 消息压缩阀值,当消息体的大小超过该阀值后,进行消息压缩。默认为 4 * 1024B
max-message-size: 4194304 # 消息体的最大允许大小。。默认为 4 * 1024 * 1024B
retry-times-when-send-failed: 2 # 同步发送消息时,失败重试次数。默认为 2 次。
retry-times-when-send-async-failed: 2 # 异步发送消息时,失败重试次数。默认为 2 次。
retry-next-server: false # 发送消息给 Broker 时,如果发送失败,是否重试另外一台 Broker 。默认为 false
access-key: # Access Key ,可阅读 https://github.com/apache/rocketmq/blob/master/docs/cn/acl/user_guide.md 文档
secret-key: # Secret Key
enable-msg-trace: true # 是否开启消息轨迹功能。默认为 true 开启。可阅读 https://github.com/apache/rocketmq/blob/master/docs/cn/msg_trace/user_guide.md 文档
customized-trace-topic: RMQ_SYS_TRACE_TOPIC # 自定义消息轨迹的 Topic 。默认为 RMQ_SYS_TRACE_TOPIC 。
# Consumer 配置项 (可以不在这里配置,不在这里配置需要在注解中配置)
启动类不需要配置,就跟使用 redis 一样。
1.4 代码
简单进行操作,做个简单的消费者和生产者进行测试。
构建一个消息类,实际开发中常发送对象消息(如订单信息、用户信息),需创建实体类并实现 Serializable 接口(避免序列化失败)。
public class Demo01Message implements Serializable {
public static final String TOPIC = "SPRING-DEMO-01";
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public String toString() {
return "Demo01Message{" +
"id=" + id +
'}';
}
}
生产者代码
@Component
public class Producer {
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 同步
* @param id
* @return
*/
public SendResult syncSend(Integer id) {
// 创建 Demo01Message 消息
Demo01Message message = new Demo01Message();
message.setId(id);
// 同步发送消息
return rocketMQTemplate.syncSend(Demo01Message.TOPIC, message);
}
/**
* 异步
* @param id
* @param callback 回调
* @return
*/
public void asyncSend(Integer id, SendCallback callback) {
// 创建 Demo01Message 消息
Demo01Message message = new Demo01Message();
message.setId(id);
rocketMQTemplate.asyncSend(Demo01Message.TOPIC, message, callback);
}
/**
* 单向发送
* @param id
*/
public void onewaySend(Integer id) {
// 创建 Demo01Message 消息
Demo01Message message = new Demo01Message();
message.setId(id);
rocketMQTemplate.sendOneWay(Demo01Message.TOPIC, message);
}
}
通过使用 RocketMQTemplate进行发送消息,以上案例测试了 3 种消息发送方式(同步、异步、单向)。
消费者代码
:::info SpringBoot 整合 RocketMQ 后,消费者无需手动启动监听,只需创建一个监听类,实现 RocketMQListener 接口,并用 @RocketMQMessageListener 注解指定订阅的主题和消费者组,Spring 会自动扫描并启动监听。
:::
@Slf4j
@Component
@RocketMQMessageListener(topic = Demo01Message.TOPIC,
consumerGroup = "GROUP-" + Demo01Message.TOPIC)
public class ConsumerDemo implements RocketMQListener<Demo01Message> {
@PostConstruct
public void init() {
log.info("消费者监听已启动...");
}
@Override
public void onMessage(Demo01Message messageExt) {
log.info("[消费者][线程号:{} 监听到消息:{}]", Thread.currentThread().getId(), messageExt);
}
}
注:这个 onMessage 的类型 Demo01Message 可以放原来的类 MessageExt
消费者的声明的所有属性通过@RocketMQMessageListener注解声明,实现 RocketMQListener 接口。
我们构建一个测试类进行擦看测试结果
@Slf4j
@SpringBootTest
class RocketProducerTest {
@Autowired
private Producer producer;
/**
* 测试同步发送
*/
@SneakyThrows
@Test
void testSyncSend() {
int id = (int) (System.currentTimeMillis() / 1000);
SendResult result = producer.syncSend(id);
log.info("[测试同步发送][发送编号:[{}] 发送结果:[{}]]", id, result);
// 阻塞等待,保证消费
new CountDownLatch(1).await();
}
@SneakyThrows
@Test
void testAsyncSend() {
int id = (int) (System.currentTimeMillis() / 1000);
producer.asyncSend(id, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info("[测试异步发送][发送编号:[{}] 发送成功,结果为:[{}]]", id, sendResult);
}
@Override
public void onException(Throwable throwable) {
log.info("[testASyncSend][发送编号:[{}] 发送异常]]", id, throwable);
}
});
// 阻塞等待,保证消费
new CountDownLatch(1).await();
}
@SneakyThrows
@Test
void testOnewaySend() {
int id = (int) (System.currentTimeMillis() / 1000);
producer.onewaySend(id);
log.info("[测试异步发送][发送编号:[{}] 发送成功, 不关心是否被消费!", id);
// 阻塞等待,保证消费
new CountDownLatch(1).await();
}
}
运行结果
更多案例查看 gitee:rocketmq-demo
2 相关配置
结合前文配置文件,补充 RocketMQ 与 SpringBoot 整合的核心配置说明(对应 application.yml),帮助大家根据业务场景灵活调整,避免盲目配置:
| 配置项 | 含义 | 默认值 | 使用场景 |
|---|---|---|---|
| rocketmq.name-server | NameServer 地址,生产者/消费者通过该地址找到 Broker | 无(必配) | 单机/集群部署均需配置,集群用分号分隔多个地址 |
| rocketmq.producer.group | 生产者组名称,同类生产者归为一组 | 无(必配) | 用于容错和负载均衡,不可与消费者组重名 |
| rocketmq.consumer.group | 消费者组名称,同类消费者归为一组 | 无(必配) | 集群模式下分摊消费,广播模式下仅用于标识 |
| rocketmq.consumer.message-model | 消费模式,CLUSTERING(集群)/BROADCASTING(广播) | CLUSTERING | 集群模式:一条消息仅被组内一个消费者消费;广播模式:组内所有消费者都能收到 |
| rocketmq.producer.retry-times-when-send-failed | 同步发送失败重试次数(不含第一次发送) | 2 | 网络波动、Broker 繁忙时,提高消息发送成功率 |
| rocketmq.consumer.consume-message-batch-max-size | 每次批量消费的消息数量 | 1 | 消息量大时,调大该值提高消费效率(不宜过大,避免内存溢出) |
3 常见问题与注意事项(避坑重点)
整合过程中,新手容易遇到各类问题,以下是高频问题及解决方案,结合参考资料中的兼容问题和实操踩坑经验整理:
3.1 常见问题及解决方案
- 问题1:项目启动失败,提示“Could not autowire. No beans of 'RocketMQTemplate' type found” 解决方案:检查 RocketMQ starter 依赖是否引入,版本是否与 SpringBoot 适配(SpringBoot 2.7.x 对应 starter 2.2.3+);检查配置文件中 rocketmq.name-server 是否配置正确。
- 问题2:消息发送成功,但消费者收不到消息 解决方案:① 检查生产者和消费者的 topic 是否一致;② 检查消费者组名称是否与 application.yml 中配置的一致;③ 检查消费模式是否正确,集群模式下若多个消费者实例,消息会分摊消费,可关闭其他实例重试;④ 检查 RocketMQ 服务是否正常运行,NameServer 与 Broker 连接是否正常。
- 问题3:发送对象消息时,消费者接收失败,提示“序列化失败” 解决方案:实体类必须实现 Serializable 接口;确保生产者和消费者的实体类全路径一致(包名、类名完全相同);避免实体类中存在不可序列化的字段(如 transient 修饰的字段)。
- 问题4:项目启动失败,提示“ApplicationContext 初始化失败” 解决方案:大概率是版本不兼容,SpringBoot 2.7.x 不可使用低于 2.2.3 版本的 RocketMQ starter;避免混合使用不同版本的 Spring 相关依赖。
- 问题5:消息消费失败,无法触发重试 解决方案:消费方法中若出现异常,需手动抛出 RuntimeException(不可捕获后不抛出),Spring 会感知异常并触发重试;检查重试次数配置(默认16次),重试达到上限后消息会进入死信队列。
3.2 注意事项
- 版本适配是关键:严格按照本文推荐的版本组合配置,避免因版本不兼容导致各类异常,具体可参考 Apache RocketMQ 官方兼容性矩阵。
- 组名称规范:生产者组和消费者组不可重名,同一业务场景的生产者/消费者归为同一组,不同业务场景使用不同的组名称。
- 生产环境配置:生产环境中,需关闭 Broker 的 autoCreateTopicEnable 配置,提前手动创建主题和队列;消息发送失败需做降级处理(如存入数据库,后续补偿发送),避免消息丢失。
- 消息重试与死信队列:消费失败会触发重试,重试达到上限后消息进入死信队列(DLQ),需手动处理死信队列中的消息,避免数据丢失。
- 配置文件规范:尽量避免硬编码,消费者组、主题等可通过配置文件读取,方便后续环境切换(开发/测试/生产)。
整合 springboot 是很简单的,使用方法跟 redis 类似,主要是需要了解在什么场景用什么消息发送机制,以及消息发送机制可能会影响的效率。
4 总结
本文详细讲解了 RocketMQ 与 SpringBoot 的完整整合流程,从环境准备、依赖配置、生产者/消费者实现,到测试验证和避坑指南,全程贴合开发实际场景,突出实操性。核心亮点是利用 SpringBoot 的自动配置特性,通过 RocketMQTemplate 和 @RocketMQMessageListener 注解,摒弃了原生 API 繁琐的实例创建和配置,让开发者能够快速实现消息的发送与接收。
整合的核心要点的是“版本适配”和“配置规范”,只要严格遵循本文的版本组合和配置要求,就能顺利完成整合。后续可基于本文的基础,扩展 RocketMQ 的高级功能,如事务消息、延迟消息、消息过滤等,适配更复杂的业务场景(如分布式事务、定时任务通知等)。