Topic通配符规则
Topic通配符规则定义消息路由键与绑定键的模式匹配逻辑,实现灵活的多条件路由。
定义
Topic交换机使用两种通配符进行路由键匹配:*匹配恰好一个单词段,#匹配零个或多个单词段。路由键以点号.分隔形成层级结构的单词序列。
通配符语法
基础规则
| 通配符 | 匹配规则 | 示例 |
|---|---|---|
* | 匹配一个单词段 | stock.*匹配stock.usd,不匹配stock.usd.nyse |
# | 匹配零个或多个单词段 | stock.#匹配stock、stock.usd、stock.usd.nyse |
匹配示例
Java
绑定键: order.us.*
匹配: order.us.created ✓
order.us.updated ✓
不匹配: order.eu.created ✗
order.us.nyse.created ✗
绑定键: order.#
匹配: order ✓
order.us ✓
order.us.created ✓
order.us.nyse.pending ✓
绑定键: *.critical
匹配: order.critical ✓
payment.critical ✓
不匹配: critical ✗(需要前面有一个单词段)
order.high.critical ✗
完整示例
Java
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.util.HashMap;
import java.util.Map;
public class TopicWildcardExample {
private static final String EXCHANGE_NAME = "topic_logs";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.exchangeDeclare(EXCHANGE_NAME, "topic", true);
// 声明队列并绑定不同通配符模式
channel.queueDeclare("queue_all", true, false, false, null);
channel.queueDeclare("queue_us", true, false, false, null);
channel.queueDeclare("queue_errors", true, false, false, null);
channel.queueDeclare("queue_payments", true, false, false, null);
// 通配符绑定示例
channel.queueBind("queue_all", EXCHANGE_NAME, "#"); // 接收所有消息
channel.queueBind("queue_us", EXCHANGE_NAME, "*.us.*"); // 匹配中间为us的三段路由键
channel.queueBind("queue_errors", EXCHANGE_NAME, "*.error"); // 匹配以error结尾的两段路由键
channel.queueBind("queue_payments", EXCHANGE_NAME, "payment.#"); // 匹配所有payment开头的消息
System.out.println("Topic bindings configured");
// 测试不同路由键的消息分发
String[] testRoutingKeys = {
"order.us.created", // -> queue_all, queue_us
"order.eu.created", // -> queue_all
"payment.error", // -> queue_all, queue_errors
"payment.us.refund", // -> queue_all, queue_us, queue_payments
"system.warning", // -> queue_all
"critical.error" // -> queue_all, queue_errors
};
for (String routingKey : testRoutingKeys) {
String message = "Test message for " + routingKey;
channel.basicPublish(EXCHANGE_NAME, routingKey, null,
message.getBytes("UTF-8"));
System.out.println("Published: " + routingKey);
}
}
}
}
消费者配置
text
import com.rabbitmq.client.*;
public class TopicConsumer {
private static final String EXCHANGE_NAME = "topic_logs";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "topic", true);
// 使用临时队列接收特定模式的消息
String queueName = channel.queueDeclare().getQueue();
// 绑定通配符路由键
channel.queueBind(queueName, EXCHANGE_NAME, "order.*.created");
System.out.println("Waiting for order creation messages...");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
String routingKey = delivery.getEnvelope().getRoutingKey();
System.out.println("[" + routingKey + "] " + message);
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
};
channel.basicConsume(queueName, false, deliverCallback, consumerTag -> {});
}
}
注意事项
#可匹配零个单词段,stock.#可匹配stock本身*必须匹配恰好一个单词段,stock.*不匹配stock本身- 路由键单词段建议使用小写字母和数字,避免特殊字符导致匹配异常
- Topic交换机匹配性能随绑定数量增加而下降,建议控制绑定总数
- 通配符匹配是贪婪的,
#会尽可能匹配更多单词段
要点总结
*匹配恰好一个单词段,#匹配零个或多个单词段- 路由键以点号分隔,形成层级结构便于通配符匹配
#作为绑定键时接收所有消息,等效于Fanout交换机- 通配符匹配性能随绑定数量增加而下降,需合理设计路由结构
- 适用于多条件过滤、主题分类、层级路由等灵活路由场景
文章存放路径:D:\git2\jwdev\articles\RABBITMQ\进阶\消息路由与绑定\Topic通配符规则.md
📝 发现内容有误?点击此处直接编辑