总览
| 模型 | 交换机类型 | 适用场景 | 特点 | 图 |
|---|---|---|---|---|
| 简单队列 | (默认) | 简单点对点 | 最简单,无路由 | ![]() |
| 工作队列 | (默认) | 任务分发、负载均衡 | 多个消费者竞争 | ![]() |
| 发布/订阅 | Fanout | 广播通知、日志收集 | 一对多广播 | ![]() |
| 路由 | Direct | 分类消息处理 | 精确路由匹配 | ![]() |
| 主题 | Topic | 复杂事件路由 | 模式匹配,最灵活 | ![]() |
1.简单模式
-
P:生产者,发送消息到消息队列
-
C:消费者:消息的接受者,会一直等待消息到来。
-
queue:消息队列,图中红色部分。类似一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从其中取出消息。

特点:
-
一对一通信
-
无交换机参与
-
自动使用默认的 Direct Exchange
java
/**
* 构建生产者,发送消息
*/
public class FooProducer {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂以及参数配置
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.1.122");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("imooc");
factory.setPassword("imooc");
// 2. 创建连接Connection
Connection connection = factory.newConnection();
// 3. 创建管道Channel
Channel channel = connection.createChannel();
// 4. 创建队列Queue(简单模式不需要交换机Exchange)
/**
* queue: 队列名
* durable: 是否持久化,true:重启后,队列依然存在,否则不存在
* exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false
* autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列
* arguments: map类型其他参数
*/
channel.queueDeclare("hello", true, false, false, null);
// 5. 向队列发送消息
/**
* exchange: 交换机名称,简单模式没有,直接设置为 ""
* routingKey: 路由key,映射路径,如果交换机是默认"",则路由key和队列名一致
* props: 配置信息
* body: 消息数据
*/
String msg = "Hello 慕课网~";
channel.basicPublish("", "hello", null, msg.getBytes());
// 7. 释放
channel.close();
connection.close();
}
}
生产者基本过程:
- 创建连接工厂以及参数配置
- 创建连接Connection
- 创建管道Channel
- 创建队列Queue(简单模式不需要交换机Exchange)
- 向队列发送消息
- 释放
- channel.close();
- connection.close();
java
/**
* 构建消费者,监听消息
*/
public class FooConsumer {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂以及参数配置
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.1.122");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("imooc");
factory.setPassword("imooc");
// 2. 创建连接Connection
Connection connection = factory.newConnection();
// 3. 创建管道Channel
Channel channel = connection.createChannel();
// 4. 创建队列Queue(简单模式不需要交换机Exchange)
/**
* queue: 队列名
* durable: 是否持久化,true:重启后,队列依然存在,否则不存在
* exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false
* autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列
* arguments: map类型其他参数
*/
channel.queueDeclare("hello", true, false, false, null);
// 5. 监听并消费消息
/**
* queue: 监听的队列名
* autoAck: 是否自动确认,true:告知mq消费者已经消费的确认通知
* callback: 回调函数,处理监听的消息
*/
Consumer consumer = new DefaultConsumer(channel) {
/**
* 重写消息配送方法
* @param consumerTag: 消息标签(标识)
* @param envelope: 信封(一些信息,比如交换机路由等信息)
* @param properties: 配置信息,和生产者的一致
* @param body: 消息数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
System.out.println("consumerTag = " + consumerTag);
System.out.println("envelope = " + envelope.toString());
System.out.println("properties = " + properties.toString());
System.out.println("body = " + new String(body));
super.handleDelivery(consumerTag, envelope, properties, body);
}
};
channel.basicConsume("hello", true, consumer);
// 不需要关闭连接,则持续监听
}
}
消费者基本过程:
- 创建连接工厂以及参数配置
- 创建连接Connection
- 创建管道Channel
- 创建队列Queue(简单模式不需要交换机Exchange)
- 监听并消费消息
- 不需要关闭连接,则持续监听
目前用的是简单模式,不需要交换机的。

2.工作队列(Work Queue)
多个消费者监听同一队列,用于任务分发。消费者接收到消息后, 通过线程池异步消费。但是一个消息只能被一个消费者获取。work queue 常用于避免消息堆积问题。工作队列没有交换机。

-
P:生产者,发布任务。
-
C1:消费者 1,领取任务并且完成任务,假设完成速度较慢(模拟耗时)
-
C2:消费者 2,领取任务并且完成任务,假设完成速度较快
适用场景:
如果任务量很大很多,而一个消费者处理不过来,则此时可以使用工作队列,比如短信发送在一个系统里会有很多场景进行发送给用户,所以量很大的时候,也可以分配给多个消费者去进行消费发短信即可。这就像上班工作量很大,就需要招人共同完成一些任务是一个道理。
特点:
-
多个消费者竞争消费,但是只能一个消费者消费
-
支持消息确认机制
-
实现负载均衡
生产者:
和简单模式的差不多,把发消息那段代码换成这个。
java
package cc.wj.test.rabbitmq.learn.work;
import cc.wj.test.rabbitmq.learn.MqConst;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* 简单模式
*
* @author wj
* @version 1.0
* @date 2026/1/21 16:11
*/
public class WorkProducer {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂以及参数配置
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.146.130");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("guest");
factory.setPassword("guest");
// 2. 创建连接Connection
Connection connection = factory.newConnection();
// 3. 创建管道Channel
Channel channel = connection.createChannel();
// 4. 创建队列Queue(简单模式不需要交换机Exchange)
/**
* queue: 队列名
* durable: 是否持久化,true:重启后,队列依然存在,否则不存在
* exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false
* autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列
* arguments: map类型其他参数
*/
channel.queueDeclare(MqConst.QUEUE_NAME_WORK, true, false, false, null);
// 5. 向队列发送消息
/**
* exchange: 交换机名称,简单模式没有,直接设置为 ""
* routingKey: 路由key,映射路径,如果交换机是默认"",则路由key和队列名一致
* props: 配置信息
* body: 消息数据
*/
for (int i = 0; i < 20; i++) {
String msg = "Hello Work~" + i;
channel.basicPublish("", MqConst.QUEUE_NAME_WORK, null, msg.getBytes());
}
// 7. 释放
channel.close();
connection.close();
}
}
消费者:
构建两个消费者:
只需要复制简单模式再修改队列名即可
java
package cc.wj.test.rabbitmq.learn.work;
import cc.wj.test.rabbitmq.learn.MqConst;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author wj
* @version 1.0
* @date 2026/1/21 16:13
*/
public class FooConsumer1 {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂以及参数配置
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.146.130");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("guest");
factory.setPassword("guest");
// 2. 创建连接Connection
Connection connection = factory.newConnection();
// 3. 创建管道Channel
Channel channel = connection.createChannel();
// 4. 创建队列Queue(简单模式不需要交换机Exchange)
/**
* queue: 队列名
* durable: 是否持久化,true:重启后,队列依然存在,否则不存在
* exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false
* autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列
* arguments: map类型其他参数
*/
channel.queueDeclare(MqConst.QUEUE_NAME_WORK, true, false, false, null);
// 5. 监听并消费消息
/**
* queue: 监听的队列名
* autoAck: 是否自动确认,true:告知mq消费者已经消费的确认通知
* callback: 回调函数,处理监听的消息
*/
Consumer consumer = new DefaultConsumer(channel) {
/**
* 重写消息配送方法
*
* @param consumerTag: 消息标签(标识)
* @param envelope: 信封(一些信息,比如交换机路由等信息)
* @param properties: 配置信息,和生产者的一致
* @param body: 消息数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
System.out.println("body = 消费者1 :" + new String(body));
super.handleDelivery(consumerTag, envelope, properties, body);
}
};
channel.basicConsume(MqConst.QUEUE_NAME_WORK, true, consumer);
// 不需要关闭连接,则持续监听
}
}
先启动消费者,在启动生成者,输出如下:


我们发现消费者是按照轮询消费的,但这种消费存在一个问题,假如 Consumer1 处理能力极快,Consumer2 (代码中休眠了 2s)处理能力极慢,这是 Consumer2 会严重拖累整体消费进度,而 Consuemr1 又早早的完成任务而无所事事。
从上面的结果可以看出,任务是平均分配的。
也就是说,不管你上个任务是否完成,我继续把后面的任务分发给你,而实际上为了效率,谁消费得越快,谁就得到越多。因此可以通过 BasicQos 方法的参数设为 1,前提是在手动 ack 的情况下才生效 ,即 autoAck = false。实现能者多劳。
java
package cc.wj.test.rabbitmq.learn.work;
import cc.wj.test.rabbitmq.learn.MqConst;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* @author wj
* @version 1.0
* @date 2026/1/21 16:13
*/
public class FooConsumer2 {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂以及参数配置
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.146.130");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("guest");
factory.setPassword("guest");
// 2. 创建连接Connection
Connection connection = factory.newConnection();
// 3. 创建管道Channel
Channel channel = connection.createChannel();
channel.basicQos(5);
// 4. 创建队列Queue(简单模式不需要交换机Exchange)
/**
* queue: 队列名
* durable: 是否持久化,true:重启后,队列依然存在,否则不存在
* exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false
* autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列
* arguments: map类型其他参数
*/
channel.queueDeclare(MqConst.QUEUE_NAME_WORK, true, false, false, null);
// 5. 监听并消费消息
/**
* queue: 监听的队列名
* autoAck: 是否自动确认,true:告知mq消费者已经消费的确认通知
* callback: 回调函数,处理监听的消息
*/
Consumer consumer = new DefaultConsumer(channel) {
/**
* 重写消息配送方法
*
* @param consumerTag: 消息标签(标识)
* @param envelope: 信封(一些信息,比如交换机路由等信息)
* @param properties: 配置信息,和生产者的一致
* @param body: 消息数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("body = 消费者2 :" + new String(body));
//确认消息
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
channel.basicConsume(MqConst.QUEUE_NAME_WORK, false, consumer);
// 不需要关闭连接,则持续监听
}
}
3.发布/订阅Publish/Subscribe-Fanout
一次向多个消费者发送消息,该模式的交换机类型为 Fanout,也称为广播。

它具有以下性质:
-
可以有多个消费者。
-
每个消费者有自己的 queue。
-
每个队列都要绑定到 Exchange。
-
生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定。
-
交换机把消息发送给绑定过的所有队列。
-
队列的消费者都能拿到消息,实现一条消息被多个消费者消费。
-
适合日志广播、事件通知
只要监听队列,所有的消费者都能消费同一个消息,这类似与公众号的订阅,比如我和你都订阅了某某的公众号,某某只要发布一个新的文章,那么我们都可以同时收到,这就是发布订阅模式。
需要注意,这里使用了交换机,因为不同的用户组可以订阅不同的队列,所以通过交换机来绑定管理并且把消息路由到不同的队列即可。
交换机的类型:
-
Fanout:广播模式,把消息发送给所有绑定的队列
-
Direct:定向 投递,把消息发送给指定的
routing key的队列 -
Topic:通配符模式,把消息交给符合
routing pattern的队列
需要注意,交换机只负责转发消息,不会存储消息,存储消息的职责是队列的。
javapackage cc.wj.test.rabbitmq.learn.publish; import cc.wj.test.rabbitmq.learn.MqConst; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import static cc.wj.test.rabbitmq.learn.MqConst.EXCHANGE_NAME_PUBLISH; /** * 简单模式 * * @author wj * @version 1.0 * @date 2026/1/21 16:11 */ public class PublishProducer { public static void main(String[] args) throws Exception { // 1. 创建连接工厂以及参数配置 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("192.168.146.130"); factory.setPort(5672); factory.setVirtualHost("/"); factory.setUsername("guest"); factory.setPassword("guest"); // 2. 创建连接Connection Connection connection = factory.newConnection(); // 3. 创建管道Channel Channel channel = connection.createChannel(); // 创建交换机 /** * exchange: 交换机名称 * type: 交换机类型 * FANOUT("fanout"): 广播模式,把消息发送给所有绑定的队列 * DIRECT("direct"): 定向投递,把消息发送给指定的`routing key`的队列 * TOPIC("topic"): 通配符模式,把消息交给符合`routing pattern`的队列 * HEADERS("headers"): 使用率不多,参数匹配 * durable: 是否持久化 * autoDelete: 是否自动删除 * internal: 内部意思,true:表示当前Exchange是RabbitMQ内部使用,用户创建的队列不会消费该类型交换机下的消息,所以我们自己使用设置为false即可 * arguments: 参数 */ channel.exchangeDeclare(EXCHANGE_NAME_PUBLISH, BuiltinExchangeType.FANOUT, true, false, false, null); // 4. 创建队列Queue /** * queue: 队列名 * durable: 是否持久化,true:重启后,队列依然存在,否则不存在 * exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false * autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列 * arguments: map类型其他参数 */ channel.queueDeclare(MqConst.QUEUE_NAME_PUBLISH1, true, false, false, null); channel.queueDeclare(MqConst.QUEUE_NAME_PUBLISH2, true, false, false, null); // 绑定交换机和队列 /** * queue * exchange * routingKey: 路由key,绑定规则,这里暂不使用(fanout本身广播给所有订阅者,所以没有路由规则,使用空字符串即可) */ channel.queueBind(MqConst.QUEUE_NAME_PUBLISH1, EXCHANGE_NAME_PUBLISH, ""); channel.queueBind(MqConst.QUEUE_NAME_PUBLISH2, EXCHANGE_NAME_PUBLISH, ""); // 5. 向队列发送消息 /** * exchange: 交换机名称,简单模式没有,直接设置为 "" * routingKey: 路由key,映射路径,如果交换机是默认"",则路由key和队列名一致 * props: 配置信息 * body: 消息数据 */ for (int i = 0; i < 20; i++) { String msg = "Hello Work~" + i; channel.basicPublish(EXCHANGE_NAME_PUBLISH, "", null, msg.getBytes()); } // 7. 释放 channel.close(); connection.close(); } }消费者:
java
package cc.wj.test.rabbitmq.learn.publish;
import cc.wj.test.rabbitmq.learn.MqConst;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author wj
* @version 1.0
* @date 2026/1/21 16:13
*/
public class PublishConsumer1 {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂以及参数配置
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.146.130");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("guest");
factory.setPassword("guest");
// 2. 创建连接Connection
Connection connection = factory.newConnection();
// 3. 创建管道Channel
Channel channel = connection.createChannel();
// 4. 创建队列Queue(简单模式不需要交换机Exchange)
/**
* queue: 队列名
* durable: 是否持久化,true:重启后,队列依然存在,否则不存在
* exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false
* autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列
* arguments: map类型其他参数
*/
channel.queueDeclare(MqConst.QUEUE_NAME_PUBLISH1, true, false, false, null);
// 5. 监听并消费消息
/**
* queue: 监听的队列名
* autoAck: 是否自动确认,true:告知mq消费者已经消费的确认通知
* callback: 回调函数,处理监听的消息
*/
Consumer consumer = new DefaultConsumer(channel) {
/**
* 重写消息配送方法
*
* @param consumerTag: 消息标签(标识)
* @param envelope: 信封(一些信息,比如交换机路由等信息)
* @param properties: 配置信息,和生产者的一致
* @param body: 消息数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
System.out.println("body = 消费者1 :" + new String(body));
super.handleDelivery(consumerTag, envelope, properties, body);
}
};
channel.basicConsume(MqConst.QUEUE_NAME_PUBLISH1, true, consumer);
// 不需要关闭连接,则持续监听
}
}
|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
|
|
|
4.路由Routing-Direct
选择性接收消息。
在 Direct 模型下,队列与交换机的绑定,不能是任意绑定了,而是要指定一个 RoutingKey(路由 key),消息的发送方在向 Exchange 发送消息时,也必须指定消息的 routing key。

-
P:生产者,向 Exchange 发送消息,发送消息时,会指定一个 routing key。
-
X:Exchange,接收生产者的消息,然后把消息递交给 与 routing key 完全匹配的队列。
-
C1:消费者,其所在队列指定了需要 routing key 为 error 的消息。
-
C2:消费者,其所在队列指定了需要 routing key 为 info、error、warning 的消息。
特点:
-
Direct Exchange
-
精确匹配路由键
-
适合分类处理
实现示例:
Exchange: direct_logs
├── Queue1 绑定键: error
├── Queue2 绑定键: warning
└── Queue3 绑定键: info, error, warning
生产者:
java
package cc.wj.test.rabbitmq.learn.route;
import cc.wj.test.rabbitmq.learn.MqConst;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import static cc.wj.test.rabbitmq.learn.MqConst.*;
/**
* 路由模式
*
* @author wj
* @version 1.0
* @date 2026/1/21 16:11
*/
public class RouteProducer {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂以及参数配置
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.146.130");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("guest");
factory.setPassword("guest");
// 2. 创建连接Connection
Connection connection = factory.newConnection();
// 3. 创建管道Channel
Channel channel = connection.createChannel();
// 创建交换机
/**
* exchange: 交换机名称
* type: 交换机类型
* FANOUT("fanout"): 广播模式,把消息发送给所有绑定的队列
* DIRECT("direct"): 定向投递,把消息发送给指定的`routing key`的队列
* TOPIC("topic"): 通配符模式,把消息交给符合`routing pattern`的队列
* HEADERS("headers"): 使用率不多,参数匹配
* durable: 是否持久化
* autoDelete: 是否自动删除
* internal: 内部意思,true:表示当前Exchange是RabbitMQ内部使用,用户创建的队列不会消费该类型交换机下的消息,所以我们自己使用设置为false即可
* arguments: 参数
*/
channel.exchangeDeclare(EXCHANGE_NAME_ROUTE,
BuiltinExchangeType.DIRECT, true, false, false, null);
// 4. 创建队列Queue
/**
* queue: 队列名
* durable: 是否持久化,true:重启后,队列依然存在,否则不存在
* exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false
* autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列
* arguments: map类型其他参数
*/
channel.queueDeclare(MqConst.QUEUE_NAME_ROUTE1, true, false, false, null);
channel.queueDeclare(MqConst.QUEUE_NAME_ROUTE2, true, false, false, null);
channel.queueDeclare(MqConst.QUEUE_NAME_ROUTE3, true, false, false, null);
// 绑定交换机和队列
/**
* queue
* exchange
* routingKey: 路由key,绑定规则,这里暂不使用(fanout本身广播给所有订阅者,所以没有路由规则,使用空字符串即可)
*/
channel.queueBind(MqConst.QUEUE_NAME_ROUTE1, EXCHANGE_NAME_ROUTE, ERROR);
channel.queueBind(MqConst.QUEUE_NAME_ROUTE2, EXCHANGE_NAME_ROUTE, WARNING);
channel.queueBind(MqConst.QUEUE_NAME_ROUTE3, EXCHANGE_NAME_ROUTE, INFO);
channel.queueBind(MqConst.QUEUE_NAME_ROUTE3, EXCHANGE_NAME_ROUTE, WARNING);
channel.queueBind(MqConst.QUEUE_NAME_ROUTE3, EXCHANGE_NAME_ROUTE, ERROR);
// 5. 向队列发送消息
/**
* exchange: 交换机名称,简单模式没有,直接设置为 ""
* routingKey: 路由key,映射路径,如果交换机是默认"",则路由key和队列名一致
* props: 配置信息
* body: 消息数据
*/
String[] logArr = {INFO, ERROR, WARNING};
for (int i = 0; i < 10; i++) {
String msg = "Hello Work~route~~~~" + i + "~~~~" + logArr[i % 3];
channel.basicPublish(EXCHANGE_NAME_ROUTE, logArr[i % 3], null, msg.getBytes());
}
// 7. 释放
channel.close();
connection.close();
}
}
消费者:
java
package cc.wj.test.rabbitmq.learn.route;
import cc.wj.test.rabbitmq.learn.MqConst;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author wj
* @version 1.0
* @date 2026/1/21 16:13
*/
public class RouteConsumer1 {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂以及参数配置
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.146.130");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("guest");
factory.setPassword("guest");
// 2. 创建连接Connection
Connection connection = factory.newConnection();
// 3. 创建管道Channel
Channel channel = connection.createChannel();
// 4. 创建队列Queue(简单模式不需要交换机Exchange)
/**
* queue: 队列名
* durable: 是否持久化,true:重启后,队列依然存在,否则不存在
* exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false
* autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列
* arguments: map类型其他参数
*/
channel.queueDeclare(MqConst.QUEUE_NAME_ROUTE1, true, false, false, null);
// 5. 监听并消费消息
/**
* queue: 监听的队列名
* autoAck: 是否自动确认,true:告知mq消费者已经消费的确认通知
* callback: 回调函数,处理监听的消息
*/
Consumer consumer = new DefaultConsumer(channel) {
/**
* 重写消息配送方法
*
* @param consumerTag: 消息标签(标识)
* @param envelope: 信封(一些信息,比如交换机路由等信息)
* @param properties: 配置信息,和生产者的一致
* @param body: 消息数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
System.out.println("body = 消费者1 :" + new String(body));
super.handleDelivery(consumerTag, envelope, properties, body);
}
};
channel.basicConsume(MqConst.QUEUE_NAME_ROUTE1, true, consumer);
// 不需要关闭连接,则持续监听
}
}
其他两个消费者类似,换队列名。
|----------------------------------------------------------------------------|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
|
|
|
|
5.Topics-topic
Topic 类型的 Exchange 与 Direct 相比,都是可以根据 RoutingKey 把消息路由到不同的队列。只不过 Topic 类型 Exchange 可以让队列在绑定 Routing key 的时候使用通配符!基于模式的路由,最灵活。
-
#:匹配一个或多个词
-
*:匹配一个词
java
user.# # 可以匹配到 user.add user.add.batch
user.* # 只能匹配到 user.add ,不能匹配到 user.add.batch

public static String TOPIC_PAY = "*.pay.*";//QUEUE_NAME_TOPIC1
public static String TOPIC_ORDER = "*.*.order";//QUEUE_NAME_TOPIC2
public static String TOPIC_GOODS = "goods.#";//QUEUE_NAME_TOPIC2
生产者:
java
package cc.wj.test.rabbitmq.learn.topic;
import cc.wj.test.rabbitmq.learn.MqConst;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import static cc.wj.test.rabbitmq.learn.MqConst.*;
/**
* 通配符模式
*
* @author wj
* @version 1.0
* @date 2026/1/21 16:11
*/
public class TopicProducer {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂以及参数配置
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.146.130");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("guest");
factory.setPassword("guest");
// 2. 创建连接Connection
Connection connection = factory.newConnection();
// 3. 创建管道Channel
Channel channel = connection.createChannel();
// 创建交换机
/**
* exchange: 交换机名称
* type: 交换机类型
* FANOUT("fanout"): 广播模式,把消息发送给所有绑定的队列
* DIRECT("direct"): 定向投递,把消息发送给指定的`routing key`的队列
* TOPIC("topic"): 通配符模式,把消息交给符合`routing pattern`的队列
* HEADERS("headers"): 使用率不多,参数匹配
* durable: 是否持久化
* autoDelete: 是否自动删除
* internal: 内部意思,true:表示当前Exchange是RabbitMQ内部使用,用户创建的队列不会消费该类型交换机下的消息,所以我们自己使用设置为false即可
* arguments: 参数
*/
channel.exchangeDeclare(EXCHANGE_NAME_TOPIC,
BuiltinExchangeType.TOPIC, true, false, false, null);
// 4. 创建队列Queue
/**
* queue: 队列名
* durable: 是否持久化,true:重启后,队列依然存在,否则不存在
* exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false
* autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列
* arguments: map类型其他参数
*/
channel.queueDeclare(QUEUE_NAME_TOPIC1, true, false, false, null);
channel.queueDeclare(MqConst.QUEUE_NAME_TOPIC2, true, false, false, null);
// 绑定交换机和队列
/**
* queue
* exchange
* routingKey: 路由key,绑定规则,这里暂不使用(fanout本身广播给所有订阅者,所以没有路由规则,使用空字符串即可)
*/
channel.queueBind(MqConst.QUEUE_NAME_TOPIC1, EXCHANGE_NAME_TOPIC, TOPIC_PAY);
channel.queueBind(MqConst.QUEUE_NAME_TOPIC2, EXCHANGE_NAME_TOPIC, TOPIC_ORDER);
channel.queueBind(MqConst.QUEUE_NAME_TOPIC2, EXCHANGE_NAME_TOPIC, TOPIC_GOODS);
// 5. 向队列发送消息
/**
* exchange: 交换机名称,简单模式没有,直接设置为 ""
* routingKey: 路由key,映射路径,如果交换机是默认"",则路由key和队列名一致
* props: 配置信息
* body: 消息数据
*/
String[] topicKeys = {
"user.pay.success", // 用户支付成功
"order.pay.failed", // 订单支付失败
"system.pay.notify.user", // 系统支付通知
"create.user.order", // 创建用户订单
"update.system.order", // 更新系统订单
"cancel.shop.order", // 取消商店订单
"goods", // 商品(最简单)
"goods.detail.info" // 商品详情信息
};
for (int i = 0; i < 10; i++) {
String msg = "Hello Work~topic~~~~" + topicKeys[i%8];
channel.basicPublish(EXCHANGE_NAME_TOPIC, topicKeys[i%8], null, msg.getBytes());
}
// 7. 释放
channel.close();
connection.close();
}
}
消费者:
java
package cc.wj.test.rabbitmq.learn.topic;
import cc.wj.test.rabbitmq.learn.MqConst;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
* @author wj
* @version 1.0
* @date 2026/1/21 16:13
*/
public class TopicConsumer1 {
public static void main(String[] args) throws Exception {
// 1. 创建连接工厂以及参数配置
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.146.130");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("guest");
factory.setPassword("guest");
// 2. 创建连接Connection
Connection connection = factory.newConnection();
// 3. 创建管道Channel
Channel channel = connection.createChannel();
// 4. 创建队列Queue(简单模式不需要交换机Exchange)
/**
* queue: 队列名
* durable: 是否持久化,true:重启后,队列依然存在,否则不存在
* exclusive: 是否独占,true:只能有一个消费者监听这个队列,一般设置为false
* autoDelete: 是否自动删除,true:当没有消费者的时候,自动删除队列
* arguments: map类型其他参数
*/
channel.queueDeclare(MqConst.QUEUE_NAME_TOPIC1, true, false, false, null);
// 5. 监听并消费消息
/**
* queue: 监听的队列名
* autoAck: 是否自动确认,true:告知mq消费者已经消费的确认通知
* callback: 回调函数,处理监听的消息
*/
Consumer consumer = new DefaultConsumer(channel) {
/**
* 重写消息配送方法
*
* @param consumerTag: 消息标签(标识)
* @param envelope: 信封(一些信息,比如交换机路由等信息)
* @param properties: 配置信息,和生产者的一致
* @param body: 消息数据
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
System.out.println("body = 消费者1 :" + new String(body));
super.handleDelivery(consumerTag, envelope, properties, body);
}
};
channel.basicConsume(MqConst.QUEUE_NAME_TOPIC1, true, consumer);
// 不需要关闭连接,则持续监听
}
}
其他另一个消费者类似,换队列名。



部分内容引用:https://xie.infoq.cn/article/f0cb0dc4d0e252e4573348ba2