【RabbitMQ】Topics 通配符模式(使用案例)

文章目录

  • [1. Topics(通配符模式)](#1. Topics(通配符模式))
  • [2. 引入依赖](#2. 引入依赖)
  • [3. 生产者代码编写](#3. 生产者代码编写)
    • [3.1 创建交换机](#3.1 创建交换机)
    • [3.2 声明队列](#3.2 声明队列)
    • [3.3 绑定交换机和队列](#3.3 绑定交换机和队列)
    • [3.4 发送消息](#3.4 发送消息)
    • [3.5 完整代码](#3.5 完整代码)
  • [4. 消费者代码编写](#4. 消费者代码编写)
    • [4.1 消费者一](#4.1 消费者一)
    • [4.2 消费者二](#4.2 消费者二)
  • [5. 运行程序](#5. 运行程序)

1. Topics(通配符模式)

Topics 和 Routing 模式的区别是:

  • topics 模式使用的交换机类型为 topic(Routing 模式使用的交换机类型为 direct)
  • topic 类型的交换机在匹配规则上进行了扩展,Binding Key 支持通配符匹配(direct 类型的交换机路由规则是 BindingKey 和 RoutingKey 完全匹配)。

在 topic 类型的交换机在匹配规则上,有些要求:

  • RoutingKey 是一系列由点 . 分隔的单词,比如 "stock.usd.nyse","nyse.vmw","quick.orange.rabbit" 等
  • BindingKey 和 RoutingKey 一样,也是点 . 分割的字符串。
  • Binding Key 中可以存在两种特殊字符串,用于模糊匹配
    • * 表示一个单词
    • # 表示多个单词(0-N个)

如下所示:

比如:

  • Binding Key 为 "d.a.b" 会同时路由到 Q1 和 Q2
  • Binding Key 为 "d.a.f" 会路由到 Q1
  • Binding Key 为 "c.e.f" 会路由到 Q2
  • Binding Key 为 "d.b.f" 会被丢弃,或者返回给生产者(需要设置 mandatory 参数)

接下来我们看看 Topic 模式的实现,步骤:

  • 1、引入依赖
  • 2、编写生产者代码
  • 3、编写消费者代码

2. 引入依赖

先引入 rabbitmq 的依赖

xml 复制代码
<!-- Source: https://mvnrepository.com/artifact/com.rabbitmq/amqp-client -->
<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.20.0</version>
    <scope>compile</scope>
</dependency>

3. 生产者代码编写

和路由模式,发布订阅模式的区别是:交换机类型不同,绑定队列的 Routing Key 不同

那么先去 Constants.java 里面定义交换机和队列。

java 复制代码
// 通配符模式
public static final String TOPIC_EXCHANGE = "topic.exchange";
public static final String TOPIC_QUEUE1 = "topic.queue1";
public static final String TOPIC_QUEUE2 = "topic.queue2";

3.1 创建交换机

定义交换机类型为 BuiltinExchangeType.TOPIC,代码如下所示:

java 复制代码
channel.exchangeDeclare(Constants.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC, true);

3.2 声明队列

代码如下所示:

java 复制代码
channel.queueDeclare(Constants.TOPIC_QUEUE1, true, false, false, null);
channel.queueDeclare(Constants.TOPIC_QUEUE2, true, false, false, null);

3.3 绑定交换机和队列

代码如下所示:

java 复制代码
// 5. 绑定队列和交换机
channel.queueBind(Constants.TOPIC_QUEUE1, Constants.TOPIC_EXCHANGE, "*.a.*");
channel.queueBind(Constants.TOPIC_QUEUE2, Constants.TOPIC_EXCHANGE, "*.*.b");
channel.queueBind(Constants.TOPIC_QUEUE2, Constants.TOPIC_EXCHANGE, "c.#");

直接按照下图来进行设定:

3.4 发送消息

还是老样子,发送消息和上面的图要对应起来。

java 复制代码
String msg = "Hello topic, my routing key is : ae.a.f";
channel.basicPublish(Constants.TOPIC_EXCHANGE, "ae.a.f",null, msg.getBytes()); // 转发到Q1

String msg_b = "Hello topic, my routing key is : ef.a.b";
channel.basicPublish(Constants.TOPIC_EXCHANGE, "ef.a.b",null, msg_b.getBytes()); // 转发到Q1和Q2

String msg_c = "Hello topic, my routing key is : c.ef.d";
channel.basicPublish(Constants.TOPIC_EXCHANGE, "c.ef.d",null, msg_c.getBytes()); // 转发到Q2

System.out.println("消息发送成功");

3.5 完整代码

代码如下所示:

java 复制代码
package topic;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import constant.Constants;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1. 建立连接
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(Constants.HOST);   // MQ所在的服务器地址
        factory.setPort(Constants.PORT);            // 端口号
        factory.setUsername(Constants.USERNAME);    // 账号
        factory.setPassword(Constants.PASSWORD);    // 密码
        factory.setVirtualHost(Constants.VIRTUAL_HOST);      // 虚拟主机
        Connection connection = factory.newConnection();

        // 2. 开启 channel 通道
        Channel channel = connection.createChannel();

        // 3. 声明交换机(使用内置的交换机即可)
        channel.exchangeDeclare(Constants.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC, true);

        // 4. 声明队列
        channel.queueDeclare(Constants.TOPIC_QUEUE1, true, false, false, null);
        channel.queueDeclare(Constants.TOPIC_QUEUE2, true, false, false, null);

        // 5. 绑定队列和交换机
        channel.queueBind(Constants.TOPIC_QUEUE1, Constants.TOPIC_EXCHANGE, "*.a.*");
        channel.queueBind(Constants.TOPIC_QUEUE2, Constants.TOPIC_EXCHANGE, "*.*.b");
        channel.queueBind(Constants.TOPIC_QUEUE2, Constants.TOPIC_EXCHANGE, "c.#");

        // 6. 发送消息
        String msg = "Hello topic, my routing key is : ae.a.f";
        channel.basicPublish(Constants.TOPIC_EXCHANGE, "ae.a.f",null, msg.getBytes()); // 转发到Q1

        String msg_b = "Hello topic, my routing key is : ef.a.b";
        channel.basicPublish(Constants.TOPIC_EXCHANGE, "ef.a.b",null, msg_b.getBytes()); // 转发到Q1和Q2

        String msg_c = "Hello topic, my routing key is : c.ef.d";
        channel.basicPublish(Constants.TOPIC_EXCHANGE, "c.ef.d",null, msg_c.getBytes()); // 转发到Q2

        System.out.println("消息发送成功");

        // 7. 资源释放
        channel.close();
        connection.close();
    }
}

4. 消费者代码编写

Topic 模式的消费者代码 和 Routing 模式代码一样,同样复制出来两份,然后修改消费的队列名称就可以了。

4.1 消费者一

代码如下所示:

java 复制代码
package topic;

import com.rabbitmq.client.*;
import constant.Constants;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class Consumer1 {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1. 建立连接
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(Constants.HOST);   // MQ所在的服务器地址
        factory.setPort(Constants.PORT);            // 端口号
        factory.setUsername(Constants.USERNAME);    // 账号
        factory.setPassword(Constants.PASSWORD);    // 密码
        factory.setVirtualHost(Constants.VIRTUAL_HOST);      // 虚拟主机
        Connection connection = factory.newConnection();

        // 2. 开启 channel 通道
        Channel channel = connection.createChannel();

        // 3. 声明队列
        channel.queueDeclare(Constants.TOPIC_QUEUE1, true, false, false, null);

        // 4. 接收消息并消费
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            // 从队列中收到消息后, 就会执行的方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                // 收到消息以后就进行打印
                System.out.println("接收到消息: " + new String(body));
            }
        };
        channel.basicConsume(Constants.TOPIC_QUEUE1, true, consumer);

        // 5. 不需要释放资源
    }
}

4.2 消费者二

代码如下所示:

java 复制代码
package topic;

import com.rabbitmq.client.*;
import constant.Constants;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class Consumer2 {
    public static void main(String[] args) throws IOException, TimeoutException {
        // 1. 建立连接
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost(Constants.HOST);   // MQ所在的服务器地址
        factory.setPort(Constants.PORT);            // 端口号
        factory.setUsername(Constants.USERNAME);    // 账号
        factory.setPassword(Constants.PASSWORD);    // 密码
        factory.setVirtualHost(Constants.VIRTUAL_HOST);      // 虚拟主机
        Connection connection = factory.newConnection();

        // 2. 开启 channel 通道
        Channel channel = connection.createChannel();

        // 3. 声明队列
        channel.queueDeclare(Constants.TOPIC_QUEUE2, true, false, false, null);

        // 4. 接收消息并消费
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            // 从队列中收到消息后, 就会执行的方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                // 收到消息以后就进行打印
                System.out.println("接收到消息: " + new String(body));
            }
        };
        channel.basicConsume(Constants.TOPIC_QUEUE2, true, consumer);

        // 5. 不需要释放资源
    }
}

5. 运行程序

先运行生产者代码

可以看到 topic.queue1 队列中,路由了两条消息。topic.queue2 队列中,路由了两条消息

exchange 下队列和 Routing Key 的绑定关系,如下所示:

对应图如下所示:

然后运行 Consumer1 消费者代码:

运行 Consumer2 消费者代码:

同时可以看到,队列中的消息已经被全部给消费完了

相关推荐
openYuanrong分布式计算引擎21 小时前
openYuanrong 打造 Agent 时代的企业级分布式底座
人工智能·分布式·ai·serverless
Jul1en_21 小时前
【Java 脚手架】封装通用工具类-1
java·spring boot·分布式·spring·spring cloud
Linux运维技术栈21 小时前
业务不停机、数据零丢失:Redis / RabbitMQ / Elasticsearch 三大核心中间件升级改造集群无缝平滑迁移
redis·elasticsearch·rabbitmq
ACP广源盛139246256731 天前
Qwen3.8-Max 开源预期下@ACP#企业级终端硬件演进机遇与 PCIe 交换芯片落地分析
大数据·人工智能·分布式·单片机·嵌入式硬件
六点_dn1 天前
RabbitMQ常见知识点总结
分布式·rabbitmq
会博通·代码搬运工1 天前
会博通API对接实战:工程企业文档分布式采集系统的技术实现与Python SDK详解
开发语言·分布式·python·线性代数·矩阵·架构·电子档案合规
逐光老顽童1 天前
第 2 章:彻底搞懂 K8s Pod——从 YAML 到调度全流程
分布式·云原生
逐光老顽童1 天前
第 1 章:Kubernetes 核心概念总览——Pod、Deployment、Service 一次搞懂
分布式·云原生
tang777891 天前
分布式爬虫优化指南:如何用代理IP把采集效率提升300%
分布式·爬虫·python·tcp/ip·分布式爬虫·爬虫代理·代理ip
学者猫头鹰2 天前
分布式事务实战教程
java·分布式