RocketMQ在Spring Boot上的基础使用

RocketMQ在Spring Boot上的基础使用

一、整合前置准备

1. 环境依赖

  • Spring Boot 版本:2.x3.x
  • RocketMQ 版本:4.9.x5.x
  • JDK 版本:1.8 及以上

2. 引入 Maven 依赖

pom.xml 中添加 RocketMQ 官方 Spring Boot Starter 依赖:

xml 复制代码
<!-- RocketMQ Spring Boot Starter 核心依赖 -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.2.3</version> <!-- 与 RocketMQ 服务端版本匹配 -->
</dependency>

<!-- 可选:测试依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

版本匹配建议:

RocketMQ 4.9.x → starter 2.2.3

RocketMQ 5.x → starter 2.3.0+


二、核心配置

1. 基础配置(application.yml)

yaml 复制代码
spring:
  application:
    name: rocketmq-spring-boot-demo

# RocketMQ 核心配置
rocketmq:
  # NameServer 地址(集群用分号分隔)
  name-server: 127.0.0.1:9876
  # 生产者配置
  producer:
    # 生产者组名(必填,建议按业务命名)
    group: demo-producer-group
    # 发送超时时间(默认 3000ms)
    send-message-timeout: 3000
    # 同步发送失败重试次数(默认 2)
    retry-times-when-send-failed: 2
    # 异步发送失败重试次数(默认 2)
    retry-times-when-send-async-failed: 2
    # 消息最大长度(默认 4194304 字节 = 4MB)
    max-message-size: 4194304
    # 压缩阈值(默认 4096 字节,超过自动压缩)
    compress-message-body-threshold: 4096
  # 消费者配置(全局默认,可在消费端注解覆盖)
  consumer:
    group: demo-consumer-group
    # 消费线程数(默认 20)
    consume-thread-min: 10
    consume-thread-max: 20
    # 批量消费最大条数(默认 1)
    consume-message-batch-max-size: 1
    # 最大重试次数(默认 -1 表示 16 次)
    max-reconsume-times: 3

2. 核心配置项说明

配置项 作用 生产建议
name-server NameServer 地址 集群环境配置多个(用分号分隔),避免单点
producer.group 生产者组名 按业务划分(如 order-producer-group)
producer.send-message-timeout 发送超时 核心业务设为 5000ms,避免超时过短
consumer.group 消费者组名 一个业务逻辑对应一个组,不可复用
consumer.max-reconsume-times 最大重试次数 非核心业务设为 3 次,核心业务设为 5 次

三、各消息类型代码示例

1. 普通消息(最基础)

1.1 生产者(同步发送)
java 复制代码
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;

@Component
public class NormalMessageProducer {

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 同步发送普通消息
     * @param topic 消息主题
     * @param msgContent 消息内容
     * @param msgKey 消息唯一键(用于追踪/幂等)
     */
    public void sendNormalMessage(String topic, String msgContent, String msgKey) {
        // 构建消息(支持自定义 Header)
        Message<String> message = MessageBuilder
                .withPayload(msgContent)
                // 设置消息 Key(必填,用于幂等/追踪)
                .setHeader(RocketMQHeaders.KEYS, msgKey)
                // 可选:设置 Tag
                .setHeader(RocketMQHeaders.TAGS, "normal_tag")
                .build();

        // 同步发送(topic:tag 格式指定 Tag)
        rocketMQTemplate.syncSend(topic + ":normal_tag", message);
        System.out.println("普通消息发送成功:" + msgKey);
    }
}
1.2 消费者
java 复制代码
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.stereotype.Component;

/**
 * 普通消息消费者
 * - consumerGroup:消费者组(必填)
 * - topic:订阅主题(必填)
 * - selectorExpression:Tag 过滤(* 表示所有)
 * - messageModel:消费模式(CLUSTERING 集群/ BROADCASTING 广播)
 * - consumeMode:消费模式(CONCURRENTLY 并发/ ORDERLY 顺序)
 */
@Component
@RocketMQMessageListener(
        consumerGroup = "demo-consumer-group",
        topic = "normal_topic",
        selectorExpression = "normal_tag",
        messageModel = MessageModel.CLUSTERING,
        consumeMode = ConsumeMode.CONCURRENTLY
)
public class NormalMessageConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String msg) {
        // 消费逻辑(需保证幂等)
        System.out.println("收到普通消息:" + msg);
        // 业务处理...
    }
}

2. 顺序消息

2.1 生产者
java 复制代码
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class OrderedMessageProducer {

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送顺序消息(按业务键哈希选择队列)
     * @param topic 主题
     * @param msgContent 内容
     * @param orderId 业务唯一键(如订单ID,保证同ID入同队列)
     */
    public void sendOrderedMessage(String topic, String msgContent, String orderId) {
        // 构建消息
        String message = "订单" + orderId + ":" + msgContent;
        
        // 发送顺序消息(指定 hashKey 为 orderId)
        rocketMQTemplate.syncSendOrderly(
                topic + ":order_tag", 
                MessageBuilder.withPayload(message).build(),
                orderId // 关键:hashKey,保证同值入同队列
        );
        System.out.println("顺序消息发送成功:" + orderId);
    }
}
2.2 消费者(必须设为顺序消费)
java 复制代码
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

@Component
@RocketMQMessageListener(
        consumerGroup = "order-consumer-group",
        topic = "order_topic",
        selectorExpression = "order_tag",
        // 核心:顺序消费必须设为 ORDERLY
        consumeMode = ConsumeMode.ORDERLY
)
public class OrderedMessageConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String msg) {
        // 单线程消费,保证顺序
        System.out.println("收到顺序消息:" + msg);
        // 业务处理(如订单创建→支付→发货)
    }
}

3. 延迟消息

3.1 生产者
java 复制代码
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class DelayMessageProducer {

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送延迟消息(固定等级)
     * @param topic 主题
     * @param msgContent 内容
     * @param delayLevel 延迟等级(1=1s,5=1m,18=2h)
     */
    public void sendDelayMessage(String topic, String msgContent, int delayLevel) {
        // 构建消息
        org.apache.rocketmq.common.message.Message rocketMsg = new org.apache.rocketmq.common.message.Message(
                topic,
                "delay_tag",
                msgContent.getBytes()
        );
        // 设置延迟等级
        rocketMsg.setDelayTimeLevel(delayLevel);

        // 发送延迟消息
        rocketMQTemplate.getProducer().send(rocketMsg);
        System.out.println("延迟消息发送成功(等级" + delayLevel + "):" + msgContent);
    }
}
3.2 消费者(与普通消息一致)
java 复制代码
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

@Component
@RocketMQMessageListener(
        consumerGroup = "delay-consumer-group",
        topic = "delay_topic",
        selectorExpression = "delay_tag"
)
public class DelayMessageConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String msg) {
        System.out.println("收到延迟消息:" + msg);
        // 业务处理(如订单超时取消)
    }
}

4. 事务消息

4.1 事务监听器(核心)
java 复制代码
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;
import org.springframework.stereotype.Component;

/**
 * 事务消息监听器
 * - txProducerGroup:对应生产者组名
 */
@RocketMQTransactionListener(txProducerGroup = "tx-producer-group")
@Component
public class TransactionListener implements RocketMQLocalTransactionListener {

    /**
     * 执行本地事务
     */
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        // 获取消息内容
        String msgContent = new String((byte[]) msg.getPayload());
        String orderId = msg.getHeaders().get("KEYS").toString();
        
        try {
            // 执行本地事务(如扣减库存、创建订单)
            boolean success = executeLocalDBTransaction(orderId);
            if (success) {
                // 提交消息
                return RocketMQLocalTransactionState.COMMIT;
            } else {
                // 回滚消息
                return RocketMQLocalTransactionState.ROLLBACK;
            }
        } catch (Exception e) {
            // 未知状态,等待回查
            return RocketMQLocalTransactionState.UNKNOWN;
        }
    }

    /**
     * 事务回查(Broker 主动调用)
     */
    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        String orderId = msg.getHeaders().get("KEYS").toString();
        // 查询本地事务状态
        boolean isSuccess = queryLocalTransactionStatus(orderId);
        return isSuccess ? RocketMQLocalTransactionState.COMMIT : RocketMQLocalTransactionState.ROLLBACK;
    }

    // 模拟本地事务执行
    private boolean executeLocalDBTransaction(String orderId) {
        // 实际业务逻辑:操作数据库/缓存等
        return true;
    }

    // 模拟查询本地事务状态
    private boolean queryLocalTransactionStatus(String orderId) {
        // 实际查询数据库状态
        return true;
    }
}
4.2 事务消息生产者
java 复制代码
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class TransactionMessageProducer {

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送事务消息
     * @param topic 主题
     * @param msgContent 内容
     * @param orderId 订单ID(消息Key)
     */
    public void sendTransactionMessage(String topic, String msgContent, String orderId) {
        // 构建消息
        Message<String> message = MessageBuilder
                .withPayload(msgContent)
                .setHeader("KEYS", orderId)
                .setHeader("TAGS", "tx_tag")
                .build();

        // 发送事务消息(最后一个参数为 arg,会传给监听器)
        rocketMQTemplate.sendMessageInTransaction(
                topic + ":tx_tag",
                message,
                null // 自定义参数,可传业务对象
        );
        System.out.println("事务消息发送成功(半消息):" + orderId);
    }
}
4.3 事务消息消费者(与普通消息一致)
java 复制代码
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;

@Component
@RocketMQMessageListener(
        consumerGroup = "tx-consumer-group",
        topic = "tx_topic",
        selectorExpression = "tx_tag"
)
public class TransactionMessageConsumer implements RocketMQListener<String> {

    @Override
    public void onMessage(String msg) {
        System.out.println("收到事务消息:" + msg);
        // 业务处理(如通知物流、更新积分)
    }
}

5. 批量消息

5.1 生产者
java 复制代码
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Component
public class BatchMessageProducer {

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 发送批量消息
     * @param topic 主题
     */
    public void sendBatchMessage(String topic) {
        // 构建批量消息列表(必须同Topic、同Tag、无延迟/事务)
        List<Message> msgList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Message msg = new Message(
                    topic,
                    "batch_tag",
                    ("批量消息" + i).getBytes()
            );
            msgList.add(msg);
        }

        // 发送批量消息
        SendResult result = rocketMQTemplate.getProducer().send(msgList);
        System.out.println("批量消息发送成功:" + result.getMsgId());
    }
}
5.2 批量消息消费者(支持批量消费)
java 复制代码
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQBatchListener;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@RocketMQMessageListener(
        consumerGroup = "batch-consumer-group",
        topic = "batch_topic",
        selectorExpression = "batch_tag",
        // 批量消费最大条数(需与配置项一致)
        consumeMessageBatchMaxSize = 10
)
public class BatchMessageConsumer implements RocketMQBatchListener<String> {

    @Override
    public void onMessage(List<String> msgs) {
        // 批量处理消息
        System.out.println("收到批量消息,共" + msgs.size() + "条:");
        msgs.forEach(msg -> System.out.println("- " + msg));
    }
}

四、测试用例(完整示例)

java 复制代码
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class RocketMQTest {

    @Resource
    private NormalMessageProducer normalMessageProducer;

    @Resource
    private OrderedMessageProducer orderedMessageProducer;

    @Resource
    private DelayMessageProducer delayMessageProducer;

    @Resource
    private TransactionMessageProducer transactionMessageProducer;

    @Resource
    private BatchMessageProducer batchMessageProducer;

    // 测试普通消息
    @Test
    public void testNormalMessage() {
        normalMessageProducer.sendNormalMessage("normal_topic", "Hello RocketMQ", "MSG_001");
    }

    // 测试顺序消息
    @Test
    public void testOrderedMessage() {
        String orderId = "ORDER_1001";
        orderedMessageProducer.sendOrderedMessage("order_topic", "创建", orderId);
        orderedMessageProducer.sendOrderedMessage("order_topic", "支付", orderId);
        orderedMessageProducer.sendOrderedMessage("order_topic", "发货", orderId);
    }

    // 测试延迟消息(等级5=1分钟)
    @Test
    public void testDelayMessage() {
        delayMessageProducer.sendDelayMessage("delay_topic", "订单超时取消", 5);
    }

    // 测试事务消息
    @Test
    public void testTransactionMessage() {
        transactionMessageProducer.sendTransactionMessage("tx_topic", "订单支付成功", "ORDER_10086");
    }

    // 测试批量消息
    @Test
    public void testBatchMessage() {
        batchMessageProducer.sendBatchMessage("batch_topic");
    }
}

五、生产级优化建议

1. 幂等性保障

  • 消费端必须基于 msgKey 做幂等(如 Redis 分布式锁、数据库唯一键);
  • 避免重复消费导致业务异常。

2. 异常处理

  • 生产者:捕获 MQClientException,实现失败重试/降级;
  • 消费者:消费失败时抛出异常,触发重试(或手动返回失败)。

3. 监控告警

  • 监控消息堆积量(brokerOffset - consumerOffset);
  • 监控发送/消费失败率、延迟时间。

4. 死信队列处理

  • 配置死信队列(默认 %DLQ%{consumerGroup});
  • 定期处理死信消息,避免消息丢失。

总结

核心关键点

  1. 配置核心name-serverproducer/consumer.group 是必填项,需按业务规范命名;
  2. 消息类型
    • 普通消息:直接发送,适配大部分场景;
    • 顺序消息:需指定 hashKey,消费端设为 ORDERLY
    • 延迟消息:仅支持固定等级,需设置 delayTimeLevel
    • 事务消息:需实现 RocketMQLocalTransactionListener,处理本地事务和回查;
    • 批量消息:需保证同Topic/Tag,消费端实现 RocketMQBatchListener
  3. 生产规范:消息 Key 必设、消费幂等必做、重试次数合理配置。
相关推荐
花花无缺2 小时前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
初次攀爬者2 小时前
RocketMQ 基础学习
后端·消息队列·rocketmq
Derek_Smart3 小时前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot
NE_STOP4 小时前
MyBatis-mybatis入门与增删改查
java
孟陬7 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
想用offer打牌7 小时前
一站式了解四种限流算法
java·后端·go
华仔啊8 小时前
Java 开发千万别给布尔变量加 is 前缀!很容易背锅
java
也些宝8 小时前
Java单例模式:饿汉、懒汉、DCL三种实现及最佳实践
java