基于阿里云RocketMQ封装库的集成技术示例

基于阿里云RocketMQ封装库的集成技术示例

整体架构

新建一个私有库,该库封装阿里云 RocketMQ 的三种协议接入方式,通过 Spring Boot 自动配置,根据 YAML 中的 protocol 字段选择不同的消费者客户端实现。

复制代码
application.yml
      │
      ▼
RocketMqProperties (@ConfigurationProperties)
      │
      ├── producer: MqProperties → ONSFactory.createProducer()
      │
      └── consumer: Map<String, MqProperties>
              │
              ▼ (根据 protocol 字段路由)
         ┌────────────┬────────────┬────────────┐
         │    TCP     │    HTTP    │    SELF    │
         ▼            ▼            ▼
  ConsumerBean   MQClient      DefaultMqPush
  (阿里云ONS)   (阿里云HTTP)   ConsumerWrapper
                                (开源RocketMQ)

注:

博客:

https://blog.csdn.net/badao_liumang_qizhi

配置结构

YAML 配置模板

yaml 复制代码
rocketmq:
  producer:
    accessKey: xxx
    secretKey: xxx
    endpoint: http://{instanceId}.{region}.mq.aliyuncs.com:80
    sendMsgTimeoutMillis: 3000   # 可选,默认 3000

  consumer:
    my-consumer-1:              # 自定义消费者名称(key)
      accessKey: xxx
      secretKey: xxx
      endpoint: http://{instanceId}.{region}.mq-internal.aliyuncs.com:8080
      topic: TOPIC_NAME         # 支持 | 分隔多个 topic
      tag: my-tag
      groupId: GID-xxx
      protocol: tcp             # tcp / http / self
      instanceId: MQ_INST_xxx   # 仅 HTTP 协议使用
      msgType: NORMAL           # 仅 SELF 协议使用(NORMAL / ORDERLY)

属性类 MqProperties

java 复制代码
public class MqProperties {
    private String endpoint;
    private String accessKey;
    private String secretKey;
    private String topic;
    private String tag;
    private String groupId;
    private String instanceId;
    private String protocol;
    private String msgType;
    private String sendMsgTimeoutMillis;
}

属性绑定关系

java 复制代码
@Configuration
@EnableConfigurationProperties(RocketMqProperties.class)
public class RocketMqConfig { ... }

@ConfigurationProperties(prefix = "rocketmq")
public class RocketMqProperties {
    private MqProperties producer;
    private Map<String, MqProperties> consumer;
}

三种协议模式对比

特性 TCP HTTP SELF
协议类型 阿里云 ONS TCP 阿里云 HTTP 开源 Apache RocketMQ
客户端类 ConsumerBean MQClient DefaultMqPushConsumerWrapper
使用 accessKey/secretKey
使用 endpoint ✅ (作为 NAMESRV_ADDR) ✅ (作为 HTTP endpoint) ✅ (作为 namesrvAddr)
使用 groupId ✅ (GROUP_ID)
使用 instanceId ✅ (区分实例)
使用 msgType ✅ (NORMAL/ORDERLY)
多 topic 支持 ✅ (用 ` ` 分隔) ✅ (用 `
消息监听接口 TcpMqListener RocketMqHttpPuller SelfBuildMqListener / SelfBuildMqOrderlyListener

生产者初始化流程

java 复制代码
// RocketMqConfig.producer() 等效逻辑
@Bean
public Producer producer() {
    MqProperties props = rocketMqProperties.getProducer();
    if (props == null) return null;

    Properties properties = new Properties();
    properties.put("AccessKey", props.getAccessKey());
    properties.put("SecretKey", props.getSecretKey());
    properties.put("NAMESRV_ADDR", props.getEndpoint());
    properties.put("SendMsgTimeoutMillis",
        StringUtils.defaultIfBlank(props.getSendMsgTimeoutMillis(), "3000"));

    Producer producer = ONSFactory.createProducer(properties);
    producer.start();
    return producer;
}

消费者初始化流程

路由逻辑

ApplicationReadyEvent 事件触发时,遍历所有消费者配置,按 protocol 路由:

java 复制代码
@EventListener
public void handleApplicationReady(ApplicationReadyEvent event) {
    Map<String, xxxRocketMqListener> beans = context.getBeansOfType(JshRocketMqListener.class);
    // 将 listeners 按 topic 分组为 listenerMap

    for (MqProperties mqProperties : rocketMqProperties.getConsumer().values()) {
        MqProtocol protocol = MqProtocol.valueOf(mqProperties.getProtocol().toUpperCase());
        switch (protocol) {
            case HTTP -> clients.add(createHttpClient(mqProperties, listenerMap));
            case TCP  -> clients.add(createTcpClient(mqProperties, listenerMap));
            case SELF -> clients.add(createSelfClient(mqProperties, listenerMap));
        }
    }

    // 启动所有客户端
    clients.forEach(xxxRocketMqConsumerClient::start);
}

TCP 模式 --- createTcpClient

java 复制代码
private xxxRocketMqConsumerClient createTcpClient(MqProperties mqProperties, Map<String, xxxRocketMqListener> listenerMap) {
    Properties properties = new Properties();
    properties.setProperty("GROUP_ID", mqProperties.getGroupId());
    properties.setProperty("AccessKey", mqProperties.getAccessKey());
    properties.setProperty("SecretKey", mqProperties.getSecretKey());
    properties.setProperty("NAMESRV_ADDR", mqProperties.getEndpoint());

    ConsumerBean consumerBean = new ConsumerBean();
    consumerBean.setProperties(properties);

    xxxRocketMqConsumerClient client = new xxxRocketMqConsumerClient(consumerBean);

    // 解析多 topic,为每个 topic 创建订阅
    List<String> topics = Lists.newArrayList(StringUtils.split(mqProperties.getTopic(), "|"));
    for (String topic : topics) {
        String key = String.format("%s_%s",
            topic, StringUtils.defaultIfBlank(mqProperties.getTag(), ""));
        xxxRocketMqListener listener = listenerMap.get(key);

        Subscription subscription = new Subscription();
        subscription.setTopic(topic);
        subscription.setExpression(mqProperties.getTag());

        Map<Subscription, MessageListener> subscriptionTable = new HashMap<>();
        subscriptionTable.put(subscription, new TcpMqListener(listener));
        consumerBean.setSubscriptionTable(subscriptionTable);
    }

    return client;
}

HTTP 模式 --- createHttpClient

java 复制代码
private xxxRocketMqConsumerClient createHttpClient(MqProperties mqProperties, Map<String, xxxRocketMqListener> listenerMap) {
    List<String> topics = Lists.newArrayList(StringUtils.split(mqProperties.getTopic(), "|"));

    MQClient mqClient = new MQClient(
        mqProperties.getEndpoint(),
        mqProperties.getAccessKey(),
        mqProperties.getSecretKey()
    );

    Map<MQConsumer, xxxRocketMqListener> map = new HashMap<>();

    for (String topic : topics) {
        String key = String.format("%s_%s",
            topic, StringUtils.defaultIfBlank(mqProperties.getTag(), ""));
        xxxRocketMqListener listener = listenerMap.get(key);

        MQConsumer consumer;
        if (StringUtils.isNoneBlank(mqProperties.getInstanceId())) {
            // 带 instanceId 的 4 参数版本
            consumer = mqClient.getConsumer(
                mqProperties.getInstanceId(), topic,
                mqProperties.getGroupId(), mqProperties.getTag());
        } else {
            // 不带 instanceId 的 3 参数版本
            consumer = mqClient.getConsumer(topic,
                mqProperties.getGroupId(), mqProperties.getTag());
        }
        map.put(consumer, listener);
    }

    return new xxxRocketMqConsumerClient(map);
}

SELF 模式 --- createSelfClient

java 复制代码
private xxxRocketMqConsumerClient createSelfClient(MqProperties mqProperties, Map<String, xxxRocketMqListener> listenerMap) {
    DefaultMqPushConsumerWrapper consumer = new DefaultMqPushConsumerWrapper(mqProperties.getGroupId());
    consumer.setNamesrvAddr(mqProperties.getEndpoint());
    consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

    xxxRocketMqConsumerClient client = new xxxRocketMqConsumerClient(consumer);

    List<String> topics = Lists.newArrayList(StringUtils.split(mqProperties.getTopic(), "|"));
    for (String topic : topics) {
        String key = String.format("%s_%s",
            topic, StringUtils.defaultIfBlank(mqProperties.getTag(), ""));
        xxxRocketMqListener listener = listenerMap.get(key);
        consumer.subscribe(topic, mqProperties.getTag());
    }

    // 根据 msgType 注册不同类型的监听器
    MqType mqType = MqType.valueOf(mqProperties.getMsgType().toUpperCase());
    switch (mqType) {
        case NORMAL  -> consumer.registerMessageListener(new SelfBuildMqListener(listener));
        case ORDERLY -> consumer.registerMessageListener(new SelfBuildMqOrderlyListener(listener));
    }

    return client;
}

业务消费者实现模板

接口定义

java 复制代码
public interface xxxRocketMqListener {
    void consume(byte[] bytes);
    String topic();
    String tag();
}

实现示例

java 复制代码
@Component
@Slf4j
public class OrderMqConsumer implements xxxRocketMqListener {

    @Value("${rocketmq.consumer.order.tag}")
    private String tag;

    @Value("${rocketmq.consumer.order.topic}")  // 或直接引用业务 topic 变量
    private String topic;

    @Override
    public void consume(byte[] bytes) {
        OrderDto order = JsonUtil.deserializeObject(bytes, new TypeReference<OrderDto>() {});
        log.info("收到订单消息: {}", order.getId());
        // 业务逻辑
    }

    @Override
    public String topic() {
        return topic;
    }

    @Override
    public String tag() {
        return tag;
    }
}

Listener 匹配机制

库通过 String.format("%s_%s", topic, tag) 生成 key,将 xxxRocketMqListener 的实现与 YAML 中的消费者配置关联起来。消费者实现类的 topic() + tag() 返回值必须与配置一致。


消息发送模板

java 复制代码
@Component
public class OrderMqSender {

    @Autowired
    private Producer producer;

    @Value("${rocketmq.producer.tag}")
    private String tag;

    @Value("${rocketmq.consumer.order.topic}")
    private String topic;

    public void send(OrderDto order) {
        byte[] body = JsonUtil.serializeObject(order).getBytes();
        Message message = new Message(topic, tag, body);
        message.setKey(String.valueOf(order.getId()));
        producer.send(message);
    }
}

生命周期管理

java 复制代码
// 启动:ApplicationReadyEvent 时启动所有 consumer client
clients.forEach(JshRocketMqConsumerClient::start);

// 销毁:ContextClosedEvent 时关闭所有 consumer client
@EventListener
public void handleContextClosed(ContextClosedEvent event) {
    clients.forEach(client -> {
        try { client.destroy(); } catch (Exception e) { ... }
    });
}

// xxxRocketMqConsumerClient 实现了 DisposableBean
public class xxxRocketMqConsumerClient implements DisposableBean {
    public void start() { ... }
    public void destroy() { ... }
}

各属性使用总结

属性 Producer TCP Consumer HTTP Consumer SELF Consumer
accessKey
secretKey
endpoint
groupId
topic
tag
instanceId
protocol --- --- ---
msgType
sendMsgTimeoutMillis

关键设计要点

  1. 多消费者支持consumer 是一个 Map,支持配置多个独立消费者,每个消费者可以有不同的协议、topic、groupId
  2. 多 topic 订阅 :单个消费者配置支持 | 分隔的多个 topic
  3. Listener 自动发现 :通过 Spring 的 getBeansOfType(xxxRocketMqListener.class) 自动收集所有实现类
  4. 延迟启动 :消费者在 ApplicationReadyEvent 之后才启动,确保所有 Bean 初始化完成
  5. 优雅停机 :监听 ContextClosedEvent 关闭所有消费者连接
相关推荐
Database_Cool_2 小时前
RAG 混合检索首选:阿里云 Lindorm 向量+全文一体化检索
数据库·阿里云·django·云计算
望江东浪3 小时前
Vector 选型与实战:vs OTel / Logstash / Fluentd 全维对比,及统一日志与指标管道的 AWS ECS 落地
云计算·aws
Akamai中国3 小时前
Akamai收购安全企业浏览器提供商LayerX
人工智能·云原生·云计算·云服务
AKAMAI18 小时前
Akamai收购安全企业浏览器提供商LayerX
人工智能·云计算
使用小功能大师21 小时前
从零到一:使用阿里云百炼搭建企业级 AI Agent 完全实战手册(2026超详细版)
人工智能·阿里云·云计算
阿里云云原生1 天前
乌镇大赛丨5 万奖金已备好!RocketMQ 等你一起打造全新 AI-Native 管控平台
apache·rocketmq
Database_Cool_1 天前
阿里云 RDS 弹性扩容:业务无感升降配实践指南
阿里云·云计算
AOwhisky1 天前
Linux(CentOS)系统管理入门笔记(第四期)——文件系统(下篇):文件与目录操作实战——cpmvmkdirrmln
linux·运维·笔记·centos·云计算·文件系统
翼龙云_cloud2 天前
阿里云国际代理商:阿里云 ECS 全维度监控配置教程
运维·阿里云·云计算·监控