RabbitMQ 中 订阅(Fanout)、路由(Direct)、通配符(Topic)模式 的示例

这三种交换机模式的核心区别在于消息如何被路由。Fanout 忽略路由键进行广播,Direct 精确匹配路由键,Topic 则支持通配符匹配。

1. Fanout(订阅/广播)模式

Fanout 交换机会将消息广播到所有绑定到它的队列,完全忽略 Routing Key。适合“一条消息需要通知所有下游”的场景,比如配置刷新、群发通知。

发送端:

// 第二个参数(Routing Key)传空字符串即可,Fanout 不关心它
rabbitTemplate.convertAndSend("fanout.exchange", "", "广播消息:系统将在 5 分钟后维护");

接收端(两个消费者,各自监听一个队列)

@Component
public class FanoutConsumer {

@RabbitListener(bindings = @QueueBinding(
value = @Queue("fanout.queue.a"),
exchange = @Exchange(name = "fanout.exchange", type = ExchangeTypes.FANOUT)
))
public void receiveA(String message) {
System.out.println("消费者A收到: " + message);
}

@RabbitListener(bindings = @QueueBinding(
value = @Queue("fanout.queue.b"),
exchange = @Exchange(name = "fanout.exchange", type = ExchangeTypes.FANOUT)
))
public void receiveB(String message) {
System.out.println("消费者B收到: " + message);
}
}

 

2. Direct(路由)模式

Direct 交换机根据 Routing Key 精确匹配 Binding Key,只有完全一致时消息才会进入对应队列。适合按级别或类型分流,比如日志按 error / info 分别投递。

接收端(声明交换机和队列的绑定关系):

@Component
public class DirectConsumer {

@RabbitListener(bindings = @QueueBinding(
value = @Queue("direct.queue.error"),
exchange = @Exchange(name = "direct.exchange", type = ExchangeTypes.DIRECT),
key = "error"
))
public void receiveError(String message) {
System.out.println("错误日志: " + message);
}

@RabbitListener(bindings = @QueueBinding(
value = @Queue("direct.queue.info"),
exchange = @Exchange(name = "direct.exchange", type = ExchangeTypes.DIRECT),
key = "info"
))
public void receiveInfo(String message) {
System.out.println("普通日志: " + message);
}
}

 

发送端:

// Routing Key 为 "error" 时,只有 direct.queue.error 会收到
rabbitTemplate.convertAndSend("direct.exchange", "error", "数据库连接失败");
// Routing Key 为 "info" 时,只有 direct.queue.info 会收到
rabbitTemplate.convertAndSend("direct.exchange", "info", "用户登录成功");

3. Topic(通配符)模式

Topic 交换机在 Direct 的基础上支持通配符。Routing Key 用 . 分隔单词,绑定键中 * 匹配一个单词,# 匹配零个或多个单词。、

接收端:

@Component
public class TopicConsumer {

// 匹配以 .news 结尾的所有路由键,如 china.news、japan.news
@RabbitListener(bindings = @QueueBinding(
value = @Queue("topic.queue.news"),
exchange = @Exchange(name = "topic.exchange", type = ExchangeTypes.TOPIC),
key = "#.news"
))
public void receiveNews(String message) {
System.out.println("新闻队列: " + message);
}

// 只匹配 china 开头的两个单词路由键,如 china.weather,但不匹配 china.sports.news
@RabbitListener(bindings = @QueueBinding(
value = @Queue("topic.queue.china"),
exchange = @Exchange(name = "topic.exchange", type = ExchangeTypes.TOPIC),
key = "china.*"
))
public void receiveChina(String message) {
System.out.println("中国相关: " + message);
}
}

发送端与路由结果:

// 路由键 china.news → 两个队列都会收到(匹配 #.news 和 china.*)
rabbitTemplate.convertAndSend("topic.exchange", "china.news", "中国新闻");

// 路由键 japan.news → 只有 topic.queue.news 收到(匹配 #.news,不匹配 china.*)
rabbitTemplate.convertAndSend("topic.exchange", "japan.news", "日本新闻");

// 路由键 china.weather → 只有 topic.queue.china 收到(匹配 china.*,#.news 不匹配)
rabbitTemplate.convertAndSend("topic.exchange", "china.weather", "中国天气");

posted @ 2026-10-30 00:17  KLAPT  阅读(11)  评论(0)    收藏  举报