rabbitmq - 交换机
功能概述
交换机介于生产者和队列之间,生产者可以通过交换机,将消息分发到一个或多个队列上。
详细描述

张图画得非常形象,生产者和消费者之间,不是直接通过队列关联,还有交换机这一层。生产者将消息传递给交换机,交换机将消息分发到不同的队列,消费者选择队列读取消息。
因为多了一层交换机,生产者和消费者的关系变得非常灵活,生产者和队列之间,可以是1-n的关系,队列和消费者,也可以是1-n的关系,所以能适配非常多复杂的业务场景。
常用的交换机
详见源码:com.rabbitmq.client.BuiltinExchangeType
Direct Exchange ,
直连交换机,通过队列名称进行精准匹配。
Fanout Exchange
扇出交换机,消息会分配给每一个与交换机关联的队列。
Topic Exchange
主题交换机,通过模糊匹配的方式,将消息分配给命中的队列。
匹配规则:
* (星号) 用来表示一个单词 (必须出现的)
# (井号) 用来表示任意数量(零个或多个)单词
细节说明
- 星号表示一个单词,而不是一个字母。
- 当一个队列的绑定键为 "#"(井号) 的时候,这个队列将会无视消息的路由键,接收所有的消息。
- 当 * (星号) 和 # (井号) 这两个特殊字符都未在绑定键中出现的时候,此时主题交换机等价于直连交换机。
- 因此,通过主题交换机,也可以实现扇形交换机和直连交换机的功能。
举几个例子:
quick.orange.rabbit:可以匹配 *.orange.* 和*.*.rabbit
lazy.orange.elephant:可以匹配 *.orange.* 和lazy.#
lazy.pink.rabbit:可以匹配lazy.#和*.*.rabbit
Header Exchange
头交换机,根据消息头进行队列匹配。
其它
Dead Letter Exchange 死信交换机,不是 BuiltinExchangeType 中的选项,但是 rabbitmq 中有这个概念,可以再去了解了解。
测试用代码
消费者的代码,基本没什么变化,主要是生产者这边需要变动。
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.TimeoutException;
/**
* @author Mr.css
* @version 2020-11-12 19:30
*/
public class ExchangePublish {
/**
* 队列名称
*/
private static final String QUEUE_NAME = "queue_name";
/**
* 路由键,交换机会根据路由键,把消息推到队列,
* 如果路由键与队列名称一致的情况,消息会被精准推送到同名的队列
*/
private static final String ROUTING_KEY = "queue_name";
/**
* 交换机名称
*/
private static final String EXCHANGE = "exchanges";
public static void main(String[] args) {
try {
Connection connection = ConnectionUtil.getConnection();
Channel channel = connection.createChannel();
// 声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// 声明交换机
channel.exchangeDeclare(EXCHANGE, BuiltinExchangeType.DIRECT);
// 声明一个绑定:队列绑定到交换机
channel.queueBind(QUEUE_NAME,EXCHANGE,ROUTING_KEY);
// 声明一个绑定:交换机绑定到交换机
// channel.exchangeBind(EXCHANGE,EXCHANGE,ROUTING_KEY);
int cnt = 10;
while (cnt-- > 0) {
String message = "This is simple queue:" + cnt;
// 通过交换机,把消息发送到推送到队列中
channel.basicPublish(EXCHANGE, ROUTING_KEY, null, message.getBytes(Charset.defaultCharset()));
System.out.println("[send]:" + message);
}
channel.close();
connection.close();
} catch (IOException | TimeoutException e) {
e.printStackTrace();
}
}
}
消费者
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @author Mr.css
* @version 2020-11-12 19:31
*/
public class ExchangeReceive {
private static final String QUEUE_NAME = "queue_name";
public static void main(String[] args) {
try {
Connection connection = ConnectionUtil.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) {
//查看消息主体内容
String message = new String(body, StandardCharsets.UTF_8);
System.out.println("[receive]:" + message);
}
};
// 设置为自动 ACK
channel.basicConsume(QUEUE_NAME, true, consumer);
} catch (IOException | ShutdownSignalException | ConsumerCancelledException | TimeoutException e) {
e.printStackTrace();
}
}
}
交换机属性
前端管理页面,新增交换机的时候,可以看到这些属性,代码上,需要多个步骤完成。
- 名称(name):exchange的名称;
- 类型(type):可选值为 direct, headers, topic, fanout;
- 持久化(durable):设置为 true,消息队列重启之后,交换机不会被删除;
- 自动删除(Auto Delete):是否自动删除,默认是 No;启用时,绑定的交换机和队列,都接触绑定的时候,自动删除该交换机;
- 内部使用(Internal): 是否内部使用,默认 NO。启用时,客户端不能直接投递消息到此交换器,只能由 rabbitmq 自己使用,一般用于 exchange 到 exchange 的绑定;
- 其它属性(Arguments):一般设置为[],不需要。
疯狂的妞妞 :每一天,做什么都好,不要什么都不做!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY