二、RocketMQ 实战:顺序消息、事务消息与 SpringBoot 集成
1. 引言
在分布式系统中,消息中间件是解耦、削峰填谷、异步化的重要基础设施。阿里巴巴开源的 Apache RocketMQ,凭借其高性能、低延迟、高可用的特性,被广泛应用于金融、电商、物流等场景。
本文将从实战角度出发,深入探讨 顺序消息 与 事务消息 的应用方式,并演示如何在 SpringBoot 中集成 RocketMQ,以便开发者快速落地生产级消息解决方案。
2. 顺序消息(Ordered Message)
2.1 背景
在某些业务场景下,消息的消费顺序至关重要。例如:
- 电商订单流程:下单 → 支付 → 发货 → 收货。
- 股票交易:挂单 → 撮合 → 成交 → 清算。
如果消息乱序消费,可能导致业务逻辑错误。
2.2 实现原理
RocketMQ 通过 队列分区 + 消费队列绑定 的方式保证顺序。
- 生产者:根据业务 Key(如订单号)选择消息发送到同一个队列。
- 消费者:一个队列只会被一个消费线程消费,从而保证同一 Key 的消息有序。
Mermaid 时序图:
2.3 代码示例
// 顺序消息发送示例
SendResult result = producer.send(
new Message("OrderTopic", "order", "1001", "创建订单".getBytes()),
(mqs, msg, arg) -> {
int queueIndex = Math.abs(arg.hashCode()) % mqs.size();
return mqs.get(queueIndex);
},
"1001" // 订单号作为路由参数
);
3. 事务消息(Transactional Message)
3.1 背景
事务消息用于解决 分布式事务一致性 问题。例如:
-
用户下单并支付,必须保证:
- 扣款成功 → 订单状态更新成功。
- 如果扣款失败 → 订单不能更新。
传统分布式事务(XA、2PC)效率低,RocketMQ 提供 事务消息机制 来实现最终一致性。
3.2 实现原理
事务消息采用 半消息 + 事务回查 的方式:
-
生产者发送半消息,Broker 暂存,不投递给消费者。
-
生产者执行本地事务(如扣款操作)。
-
根据事务结果提交:
- Commit:消息正式投递给消费者。
- Rollback:消息丢弃。
- Unknown:Broker 会定期回查事务状态。
Mermaid 流程图:
3.3 代码示例
// 事务消息发送示例
TransactionMQProducer producer = new TransactionMQProducer("tx-producer-group");
producer.setTransactionListener(new TransactionListener() {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
// 执行本地事务,例如扣款
boolean success = doBusiness();
return success ? LocalTransactionState.COMMIT_MESSAGE
: LocalTransactionState.ROLLBACK_MESSAGE;
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
// Broker 回查事务状态
return LocalTransactionState.COMMIT_MESSAGE;
}
});
producer.start();
producer.sendMessageInTransaction(new Message("TxTopic", "tag", "事务消息".getBytes()), null);
4. SpringBoot 集成 RocketMQ
4.1 引入依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
4.2 配置文件
rocketmq:
name-server: 127.0.0.1:9876
producer:
group: demo-producer-group
4.3 生产者示例
@Service
public class OrderProducer {
@Resource
private RocketMQTemplate rocketMQTemplate;
public void sendOrderMessage(String orderId, String msg) {
rocketMQTemplate.syncSendOrderly(
"OrderTopic",
MessageBuilder.withPayload(msg).build(),
orderId // 使用订单号作为分区键
);
}
}
4.4 消费者示例
@RocketMQMessageListener(topic = "OrderTopic", consumerGroup = "order-consumer-group")
@Service
public class OrderConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("收到消息:" + message);
}
}
5. 实践中的问题与优化
-
顺序消息并发度不足
- 一个队列只能由一个线程消费,可能成为瓶颈。
- 解决:根据业务 Key 合理分区,增加队列数。
-
事务消息回查频繁
- 如果事务状态无法及时确认,Broker 会频繁回查。
- 解决:优化本地事务逻辑,确保尽快返回结果。
-
消息堆积问题
- 消费能力不足会导致堆积。
- 解决:水平扩展消费者,提升并行度。
好的 ✅ 我来为你整理一个 可直接运行的 SpringBoot + RocketMQ Demo 工程源码,涵盖 顺序消息 和 事务消息 的生产与消费示例。
6. RocketMQ SpringBoot Demo 工程结构
rocketmq-demo
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com.example.rocketmqdemo
│ │ │ ├── RocketmqDemoApplication.java // 启动类
│ │ │ ├── producer
│ │ │ │ ├── OrderProducer.java // 顺序消息生产者
│ │ │ │ └── TxProducer.java // 事务消息生产者
│ │ │ └── consumer
│ │ │ ├── OrderConsumer.java // 顺序消息消费者
│ │ │ └── TxConsumer.java // 事务消息消费者
│ │ └── resources
│ │ └── application.yml // 配置文件
1. Maven 依赖(pom.xml)
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>rocketmq-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version>
</parent>
<dependencies>
<!-- SpringBoot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- RocketMQ SpringBoot Starter -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!-- Lombok (可选) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. 配置文件(application.yml)
spring:
application:
name: rocketmq-demo
rocketmq:
name-server: 127.0.0.1:9876
producer:
group: demo-producer-group
3. 启动类
package com.example.rocketmqdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RocketmqDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RocketmqDemoApplication.class, args);
}
}
4. 顺序消息
4.1 生产者(OrderProducer.java)
package com.example.rocketmqdemo.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
@Service
public class OrderProducer {
@Autowired
private RocketMQTemplate rocketMQTemplate;
public void sendOrderMessage(String orderId, String msg) {
rocketMQTemplate.syncSendOrderly(
"OrderTopic",
MessageBuilder.withPayload(msg).build(),
orderId // 按订单号分区
);
System.out.println("发送顺序消息: " + msg);
}
}
4.2 消费者(OrderConsumer.java)
package com.example.rocketmqdemo.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
@Service
@RocketMQMessageListener(topic = "OrderTopic", consumerGroup = "order-consumer-group")
public class OrderConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("消费顺序消息: " + message);
}
}
5. 事务消息
5.1 生产者(TxProducer.java)
package com.example.rocketmqdemo.producer;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
@Service
public class TxProducer {
@Autowired
private RocketMQTemplate rocketMQTemplate;
public void sendTransactionMessage(String content) {
Message<String> msg = MessageBuilder.withPayload(content).build();
rocketMQTemplate.sendMessageInTransaction("TxTopic", msg, null);
System.out.println("发送事务消息: " + content);
}
}
5.2 本地事务监听器(TxListener.java)
package com.example.rocketmqdemo.producer;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.springframework.messaging.Message;
@RocketMQTransactionListener(txProducerGroup = "demo-producer-group")
public class TxListener implements RocketMQLocalTransactionListener {
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
System.out.println("执行本地事务: " + msg.getPayload());
// 模拟业务逻辑
boolean success = true;
return success ? RocketMQLocalTransactionState.COMMIT
: RocketMQLocalTransactionState.ROLLBACK;
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
System.out.println("回查事务消息: " + msg.getPayload());
return RocketMQLocalTransactionState.COMMIT;
}
}
5.3 消费者(TxConsumer.java)
package com.example.rocketmqdemo.consumer;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
@Service
@RocketMQMessageListener(topic = "TxTopic", consumerGroup = "tx-consumer-group")
public class TxConsumer implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
System.out.println("消费事务消息: " + message);
}
}
7. 测试
可以在 RocketmqDemoApplication 启动后,写一个简单的 CommandLineRunner 测试:
@Bean
CommandLineRunner test(OrderProducer orderProducer, TxProducer txProducer) {
return args -> {
// 发送顺序消息
orderProducer.sendOrderMessage("1001", "订单创建");
orderProducer.sendOrderMessage("1001", "订单支付");
orderProducer.sendOrderMessage("1001", "订单发货");
// 发送事务消息
txProducer.sendTransactionMessage("事务消息: 用户下单并扣款");
};
}
运行后,你会看到控制台输出:
发送顺序消息: 订单创建
消费顺序消息: 订单创建
发送顺序消息: 订单支付
消费顺序消息: 订单支付
发送事务消息: 事务消息: 用户下单并扣款
执行本地事务: 事务消息: 用户下单并扣款
消费事务消息: 事务消息: 用户下单并扣款
8. 总结
本文介绍了 RocketMQ 中两大核心特性:
- 顺序消息:保障业务消息严格顺序。
- 事务消息:解决分布式事务一致性问题。
并演示了如何通过 SpringBoot 集成 RocketMQ,从而快速构建生产级的消息驱动应用。
在实践中,还需关注 消息可靠性、消费并发度、事务回查优化 等问题,以保证系统的稳定性与高可用性。
本文来自博客园,作者:NeoLshu,转载请注明原文链接:https://www.cnblogs.com/neolshu/p/19120593

浙公网安备 33010602011771号