1、路由模式
官网的路由(Routing)模式流程示意图:

该模式也需要加入交换机,指定其类型为direct 。队列在绑定交换机时要指定routing key (路由键),消息会转发到符合routing key的队列。交换机根据routingKey进行完全匹配,如果匹配失败则丢弃消息。
例子:
队列 A 绑定 error
队列 B 绑定 info、error
- 发送 routing‑key=error:队列 A、队列 B 同时收到
- 发送 routing‑key=info:只有队列 B 收到
可以实现选择性投递,而不是无脑广播。
场景:日志系统,error 日志发给告警队列。
xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version>
<relativePath/>
</parent>
<groupId>com.demo</groupId>
<artifactId>rabbitmq_direct</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>rabbitmq_direct</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- rabbitmq -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- web 测试接口 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
java
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
listener:
simple:
acknowledge-mode: manual
server:
port: 8080`在这里插入代码片
java
package com.demo.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 关键点:同一个队列可以绑定多个不同的 binding‑key
*/
@Configuration
public class DirectConfig {
//交换机名称
public static final String DIRECT_EXCHANGE = "direct_exchange_log";
//队列
public static final String QUEUE_LOG = "direct_queue_log";
public static final String QUEUE_ALERT = "direct_queue_alert";
//1.声明Direct交换机
@Bean
public DirectExchange directExchange(){
return new DirectExchange(DIRECT_EXCHANGE,true,false);
}
//2.声明日志队列
@Bean
public Queue logQueue(){
return new Queue(QUEUE_LOG,true);
}
//3.声明告警队列
@Bean
public Queue alertQueue(){
return new Queue(QUEUE_ALERT,true);
}
/**
* 日志队列绑定交换机
* binding‑key: info,warning,error 三种级别日志都接收
*/
@Bean
public Binding bindingLogInfo(DirectExchange directExchange,Queue logQueue){
return BindingBuilder.bind(logQueue).to(directExchange).with("info");
}
@Bean
public Binding bindingLogWarning(DirectExchange directExchange,Queue logQueue){
return BindingBuilder.bind(logQueue).to(directExchange).with("warning");
}
@Bean
public Binding bindingLogError(DirectExchange directExchange,Queue logQueue){
return BindingBuilder.bind(logQueue).to(directExchange).with("error");
}
/**
* 告警队列只绑定 error,只接收错误日志
*/
@Bean
public Binding bindingAlertError(DirectExchange directExchange,Queue alertQueue){
return BindingBuilder.bind(alertQueue).to(directExchange).with("error");
}
}
java
package com.demo.producer;
import com.demo.config.DirectConfig;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DirectProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* level:info / warning / error
* http://127.0.0.1:8080/sendLog/error
*/
@GetMapping("/sendLog/{level}")
public String sendLog(@PathVariable String level){
String msg = "日志内容,日志级别:" + level;
rabbitTemplate.convertAndSend(DirectConfig.DIRECT_EXCHANGE,level,msg);
System.out.println("生产者发送消息,routing‑key:" + level);
return "消息发送成功,routing‑key=" + level;
}
}
java
package com.demo.consumer;
import com.demo.config.DirectConfig;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class AlertConsumer {
@RabbitListener(queues = DirectConfig.QUEUE_ALERT)
public void consume(String msg, Message message, Channel channel) throws IOException {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
System.out.println("【告警队列消费者】收到消息:" + msg);
Thread.sleep(300);
channel.basicAck(deliveryTag,false);
System.out.println("【告警队列消费者】消费完成ACK");
}catch (Exception e){
channel.basicNack(deliveryTag,false,true);
System.out.println("【告警队列消费者】消费失败");
}
}
}
java
package com.demo.consumer;
import com.demo.config.DirectConfig;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class LogConsumer {
@RabbitListener(queues = DirectConfig.QUEUE_LOG)
public void consume(String msg, Message message, Channel channel) throws IOException {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
System.out.println("【日志队列消费者】收到消息:" + msg);
Thread.sleep(300);
channel.basicAck(deliveryTag,false);
System.out.println("【日志队列消费者】消费完成ACK");
}catch (Exception e){
channel.basicNack(deliveryTag,false,true);
System.out.println("【日志队列消费者】消费失败");
}
}
}
java
package com.demo;
/**
* Hello world!
*
*/
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DirectApplication {
public static void main(String[] args) {
SpringApplication.run(DirectApplication.class,args);
}
}
- 发送 error 日志:
http://127.0.0.1:8080/sendLog/error
结果:日志队列 + 告警队列两个消费者都会收到消息
java
2026-08-17 20:24:35.174 INFO 5008 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-08-17 20:24:35.174 INFO 5008 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2026-08-17 20:24:35.174 INFO 5008 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
生产者发送消息,routing‑key:error
【告警队列消费者】收到消息:日志内容,日志级别:error
【日志队列消费者】收到消息:日志内容,日志级别:error
【日志队列消费者】消费完成ACK
【告警队列消费者】消费完成ACK

java
2026-08-17 20:24:35.174 INFO 5008 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-08-17 20:24:35.174 INFO 5008 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2026-08-17 20:24:35.174 INFO 5008 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
生产者发送消息,routing‑key:info
【日志队列消费者】收到消息:日志内容,日志级别:info
【日志队列消费者】消费完成ACK
2、主题模式
架构
生产者 → Topic 交换机 → 队列使用带通配符的binding‑key订阅消息
*匹配一个单词#匹配 0 个或多个单词
routing‑key 使用.分割单词,例如order.create.pay
示例:
- 队列 1 绑定
order.#→ 接收所有订单相关消息 - 队列 2 绑定
*.pay→ 接收所有支付事件
Topic = Direct + Fanout 的综合体,灵活最强,微服务事件总线首选。
业务示例:订单事件消息
order.create订单创建order.pay订单支付order.cancel订单取消goods.stock.reduce库存扣减
xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version>
<relativePath/>
</parent>
<groupId>com.demo</groupId>
<artifactId>rabbitmq_topic</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>rabbitmq_topic</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- rabbitmq -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- web 测试接口 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
java
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
listener:
simple:
acknowledge-mode: manual
server:
port: 8080
java
package com.demo.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TopicConfig {
//主题交换机名称
public static final String TOPIC_EXCHANGE = "topic_exchange_event";
//队列1:订单队列,订阅所有订单事件 order.#
public static final String QUEUE_ORDER = "topic_queue_order";
//队列2:支付队列,只订阅一级后缀为pay的事件 *.pay
public static final String QUEUE_PAY = "topic_queue_pay";
//1.声明Topic交换机
@Bean
public TopicExchange topicExchange(){
return new TopicExchange(TOPIC_EXCHANGE,true,false);
}
//2.声明订单队列
@Bean
public Queue orderQueue(){
return new Queue(QUEUE_ORDER,true);
}
//3.声明支付队列
@Bean
public Queue payQueue(){
return new Queue(QUEUE_PAY,true);
}
/**
* 订单队列绑定,binding‑key = order.#
* 匹配所有以 order. 开头的 routing‑key
*/
@Bean
public Binding bindingOrder(TopicExchange topicExchange,Queue orderQueue){
return BindingBuilder.bind(orderQueue).to(topicExchange).with("order.#");
}
/**
* 支付队列绑定,binding‑key = *.pay
* 只能匹配两段,第二段是pay,例如 order.pay、goods.pay
*/
@Bean
public Binding bindingPay(TopicExchange topicExchange,Queue payQueue){
return BindingBuilder.bind(payQueue).to(topicExchange).with("*.pay");
}
}
java
package com.demo.producer;
import com.demo.config.TopicConfig;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TopicProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 测试地址示例:
* http://127.0.0.1:8080/sendTopic/order.create
* http://127.0.0.1:8080/sendTopic/order.pay
* http://127.0.0.1:8080/sendTopic/order.cancel
* http://127.0.0.1:8080/sendTopic/goods.pay
* http://127.0.0.1:8080/sendTopic/order.create.pay.success
*/
@GetMapping("/sendTopic/{routingKey}")
public String sendTopicMsg(@PathVariable String routingKey){
String msg = "事件消息,routing‑key = " + routingKey;
rabbitTemplate.convertAndSend(TopicConfig.TOPIC_EXCHANGE,routingKey,msg);
System.out.println("生产者发送消息:" + msg);
return "发送成功,routing‑key:"+routingKey;
}
}
java
package com.demo.consumer;
import com.demo.config.TopicConfig;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class OrderConsumer {
@RabbitListener(queues = TopicConfig.QUEUE_ORDER)
public void consume(String msg, Message message, Channel channel) throws IOException {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try{
System.out.println("【订单队列消费者】收到消息:"+msg);
Thread.sleep(300);
channel.basicAck(deliveryTag,false);
System.out.println("【订单队列消费者】消费完成ACK");
}catch (Exception e){
channel.basicNack(deliveryTag,false,true);
System.out.println("【订单队列消费者】消费失败");
}
}
}
java
package com.demo.consumer;
import com.demo.config.TopicConfig;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class PayConsumer {
@RabbitListener(queues = TopicConfig.QUEUE_PAY)
public void consume(String msg, Message message, Channel channel) throws IOException {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try{
System.out.println("【支付队列消费者】收到消息:"+msg);
Thread.sleep(300);
channel.basicAck(deliveryTag,false);
System.out.println("【支付队列消费者】消费完成ACK");
}catch (Exception e){
channel.basicNack(deliveryTag,false,true);
System.out.println("【支付队列消费者】消费失败");
}
}
}
java
package com.demo;
/**
* Hello world!
*
*/
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TopicApplication {
public static void main(String[] args) {
SpringApplication.run(TopicApplication.class,args);
}
}

java
2026-08-17 20:39:11.869 INFO 7336 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-08-17 20:39:11.869 INFO 7336 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2026-08-17 20:39:11.869 INFO 7336 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
生产者发送消息:事件消息,routing‑key = order.create
【订单队列消费者】收到消息:事件消息,routing‑key = order.create
【订单队列消费者】消费完成ACK

java
生产者发送消息:事件消息,routing‑key = order.pay
【订单队列消费者】收到消息:事件消息,routing‑key = order.pay
【支付队列消费者】收到消息:事件消息,routing‑key = order.pay
【支付队列消费者】消费完成ACK
【订单队列消费者】消费完成ACK

java
生产者发送消息:事件消息,routing‑key = order.cancel
【订单队列消费者】收到消息:事件消息,routing‑key = order.cancel
【订单队列消费者】消费完成ACK

