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", "中国天气");

浙公网安备 33010602011771号