使用 RocketMQ 实现基于标签过滤的消息队列生产和消费


在分布式系统中,消息队列(Message Queue, MQ)是系统间通信、解耦的重要工具。通过标签(Tag)过滤,RocketMQ 可以让消费者有选择性地订阅感兴趣的消息,从而大大降低系统的通信成本和复杂度。本文将通过实例代码演示如何使用 RocketMQ 实现基于标签过滤的消息生产和消费。


1. 环境准备

在开始之前,请确保以下准备工作已完成:

  1. 安装并启动 RocketMQ 服务(包括 NameServer 和 Broker)。
  2. 在项目中引入 RocketMQ 的相关依赖。

假设我们已经在 pom.xml 文件中添加了以下依赖:

<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.9.3</version>
</dependency>

我们还需要在项目中定义 NameServer 地址。可以使用一个常量类 MqConstant 来存储该信息:

package com.takumilove.constant;

public class MqConstant {
    public static final String NAME_SRV_ADDR = "localhost:9876"; // 替换为实际的 NameServer 地址
}

请将 localhost 替换为你的服务器地址,并确保防火墙已放行相关端口。


2. 生产者代码示例

生产者的主要任务是将消息发送到指定的主题(Topic)中,并为消息指定不同的标签(Tag),从而实现标签过滤。

以下是一个简单的消息生产者示例代码,它发送两条消息到 tagTopic 主题中,分别携带 vip1vip2 标签。

package com.takumilove.demo;

import com.takumilove.constant.MqConstant;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.junit.Test;

/**
 * 标签过滤生产者示例
 */
public class GTagTest {

    @Test
    public void tagProducer() throws Exception {
        // 1. 创建生产者实例并指定生产者组名
        DefaultMQProducer producer = new DefaultMQProducer("tag_producer_group");
        
        // 2. 设置 NameServer 地址
        producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
        
        // 3. 启动生产者
        producer.start();
        
        // 4. 创建并发送带有标签的消息
        Message message1 = new Message("tagTopic", "vip1", "我是vip1的文章".getBytes());
        Message message2 = new Message("tagTopic", "vip2", "我是vip2的文章".getBytes());
        
        producer.send(message1);
        producer.send(message2);
        
        System.out.println("消息发送成功");
        
        // 5. 关闭生产者
        producer.shutdown();
    }
}

说明

  1. 创建 DefaultMQProducer 实例,并指定生产者组名 tag_producer_group
  2. 设置 NameServer 地址,并启动生产者。
  3. 创建消息,并为每条消息指定标签 vip1vip2,然后将消息发送到 tagTopic 主题中。
  4. 成功发送消息后,关闭生产者。

3. 消费者代码示例

接下来,我们编写两个消费者实例来消费不同标签的消息。

3.1 消费者1:只订阅 vip1 标签的消息

package com.takumilove.demo;

import com.takumilove.constant.MqConstant;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.junit.Test;

import java.util.List;

public class GTagConsumerTest {

    @Test
    public void tagConsumer1() throws Exception {
        // 1. 创建消费者实例并指定消费者组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("tag-consumer-group-a");
        
        // 2. 设置 NameServer 地址
        consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
        
        // 3. 订阅指定主题和标签
        consumer.subscribe("tagTopic", "vip1");
        
        // 4. 注册消息监听器
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                                                            ConsumeConcurrentlyContext context) {
                System.out.println("我是vip1的消费者,我正在消费消息: " + new String(msgs.get(0).getBody()));
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        
        // 5. 启动消费者
        consumer.start();
        System.out.println("vip1 消费者启动成功");

        // 阻塞当前线程,保持消费者运行
        System.in.read();
    }
}

3.2 消费者2:订阅 vip1vip2 标签的消息

@Test
public void tagConsumer2() throws Exception {
    // 1. 创建消费者实例并指定消费者组名
    DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("tag-consumer-group-b");
    
    // 2. 设置 NameServer 地址
    consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
    
    // 3. 订阅指定主题和多个标签(使用 `||` 分隔符)
    consumer.subscribe("tagTopic", "vip1||vip2");
    
    // 4. 注册消息监听器
    consumer.registerMessageListener(new MessageListenerConcurrently() {
        @Override
        public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                                                        ConsumeConcurrentlyContext context) {
            System.out.println("我是vip1或vip2的消费者,我正在消费消息: " + new String(msgs.get(0).getBody()));
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        }
    });
    
    // 5. 启动消费者
    consumer.start();
    System.out.println("vip1 和 vip2 消费者启动成功");

    // 阻塞当前线程,保持消费者运行
    System.in.read();
}

说明

  1. tagConsumer1 只订阅 vip1 标签的消息,并打印消费结果。
  2. tagConsumer2 订阅 vip1vip2 标签的消息,并对所有匹配标签的消息进行消费和打印。

4. 运行示例

  1. 启动 RocketMQ 的 NameServer 和 Broker。
  2. 运行生产者方法 tagProducer() 发送消息。
  3. 分别运行 tagConsumer1()tagConsumer2(),观察控制台输出。

通过上述步骤,可以看到 tagConsumer1 只消费了 vip1 标签的消息,而 tagConsumer2 消费了 vip1vip2 标签的消息。


5. 总结

本文通过实际代码示例,详细介绍了如何使用 RocketMQ 实现基于标签过滤的消息生产和消费。通过标签过滤,消费者可以只接收感兴趣的消息,从而降低无用消息的传输,提高系统的性能和效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Takumilovexu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值