RabbitMQ入门_04_Exchange & Binding
如果你比较细心,你会发现 HelloWorld 例子中的 Sender 只申明了一个 hello 队列,然后就开始向默认 Exchange 发送路由键为 hello 的消息。按照之前 AMQP 基本概念介绍,消息到了 Exchange 后需要按照 Binding 提供的分发依据将消息分发到队列中。那么问题来了,在这段代码中,Binding 在哪儿?
在回答这个问题前,我们干脆先实现一个新的 direct 类型的 Exchange,看看非默认的 Exchange 是怎样工作的,毕竟,多年的经验告诉我们,系统提供的默认对象总是有额外的逻辑。
gordon.study.rabbitmq.helloworld2.NewExchangeSender.java
public class NewExchangeSender {
private static final String EXCHANGE_NAME = "p2p";
private String queueName;
private String routingKey;
private boolean declare;
public NewExchangeSender(String queueName, String routingKey, boolean declare) {
this.queueName = queueName;
this.routingKey = routingKey;
this.declare = declare;
}
public void work() throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
if (declare) {
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
channel.queueDeclare(queueName, false, false, false, null);
channel.queueBind(queueName, EXCHANGE_NAME, routingKey);
}
for (int i = 0; i < 5;) {
String message = "NO. " + ++i;
TimeUnit.MILLISECONDS.sleep(1000);
channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes("UTF-8"));
System.out.printf("(%1$s)[===>%2$s ] %3$s\n", "NESender", EXCHANGE_NAME + ":" + queueName, message);
}
channel.basicPublish(EXCHANGE_NAME, routingKey, null, "fin".getBytes("UTF-8"));
channel.close();
connection.close();
}
}
代码第24行申明了一个新的 Exchange,名字为 p2p,类型为 direct。
第25行申请了一个队列。
在第26行,通过 queueBind 方法,将队列绑定到 p2p Exchange 上,同时指定路由键。
gordon.study.rabbitmq.helloworld2.NewExchangeReceiver.java
public class NewExchangeReceiver {
private static final String EXCHANGE_NAME = "p2p";
private String queueName;
private String routingKey;
private boolean declare;
public NewExchangeReceiver(String queueName, String routingKey, boolean declare) {
this.queueName = queueName;
this.routingKey = routingKey;
this.declare = declare;
}
public void work() throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
final Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
if (declare) {
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
channel.queueDeclare(queueName, false, false, false, null);
channel.queueBind(queueName, EXCHANGE_NAME, routingKey);
}
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
if ("fin".equals(message)) {
connection.close();
return;
}
System.out.printf(" [ %2$s<===](%1$s) %3$s\n", "NEReceiver", queueName, message);
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
}
}
};
channel.basicConsume(queueName, true, consumer);
}
}
NewExchangeSender 与 NewExchangeReceiver 的实现和 HelloWorld 例子基本一致,除了申明了新的 Exchange,以及增加了 fin 消息(法语结束的意思)通知 Consumer 关闭。
目前我试出来的终止 Consumer 的方法就是通过第35行 connection.close 方法关闭连接,那么连接上的信道(Channel),以及基于信道的 Consumer,自然都会关闭。
接下来我们开始试验:
gordon.study.rabbitmq.helloworld2.Test01.java
public class Test01 {
public static void main(String[] args) throws Exception {
NewExchangeReceiver receiver = new NewExchangeReceiver("hello2", "hello2", true);
receiver.work();
NewExchangeSender sender = new NewExchangeSender("hello2", "hello2", true);
sender.work();
}
}
Test01 申明队列 hello2,并将队列通过路由键 hello2 绑定到 p2p Exchange 上。Sender 通过 basicPublish 方法将消息发送到 p2p Exchange,并指定路由键为 hello2。对于这些消息,p2p Exchange 能够查询到目前只有 hello2 队列通过 hello2 路由键绑定到自己,因此会将这些消息分发到 hello2 队列中。
执行 main 方法,一切如预料的运行:消息最终发送到 hello2 队列,被 Consumer 全部消费掉。
再看一个例子:
gordon.study.rabbitmq.helloworld2.Test02OldQueue.java
public class Test02OldQueue {
public static void main(String[] args) throws Exception {
NewExchangeReceiver receiver = new NewExchangeReceiver("hello", "hello", true);
receiver.work();
NewExchangeSender sender = new NewExchangeSender("hello", "hello", true);
sender.work();
}
}
Test02OldQueue 申明之前已经在 HelloWorld 例子中申明过的 hello 队列,同时指定路由键为 hello。执行 main 方法发现:消息最终发送到 hello 队列,被 Consumer 全部消费掉。
由此我们可以看出,队列并不属于 Exchange,队列有自己的生命周期管理,与 Exchange 之间完全通过 Binding 关联。实际上一个队列可以通过多个 Binding 关联到不同的 Exchange,甚至可以通过多个 Binding 关联到同一个 Exchange。
我们前面都刻意的让绑定键与队列名一致,但是按照前面的分析,这两者完全可以不一致,只要保证队列绑定到 Exchange 时使用的绑定键与消息发送时指定的绑定键一致就可以了,下面的例子证明了这点:
gordon.study.rabbitmq.helloworld2.Test03RoutingKey.java
public class Test03RoutingKey {
public static void main(String[] args) throws Exception {
NewExchangeReceiver receiver = new NewExchangeReceiver("hello", "abc", true);
receiver.work();
NewExchangeSender sender = new NewExchangeSender("hello", "abc", true);
sender.work();
}
}
绑定键是 abc,一样能让所有的消息通过 hello 队列发送给消费方。
最后再看一下申明的问题:
gordon.study.rabbitmq.helloworld2.Test04NoDeclare.java
public class Test04NoDeclare {
public static void main(String[] args) throws Exception {
NewExchangeReceiver receiver = new NewExchangeReceiver("hello", "abc", false);
receiver.work();
NewExchangeSender sender = new NewExchangeSender("hello", "abc", false);
sender.work();
}
}
我们不再申明 Exchange、队列和 Binding,这段代码依然可以执行,是因为我们在 Test03RoutingKey 中已经申明过了,只要 RabbitMQ 没有重启,这些模型将会一直生效。
AMQP 模型到底是交给 Publisher 申明,还是交给 Consumer 申明,还是直接在 RabbitMQ 中预先创建,这是使用 RabbitMQ 时必须考虑的问题。没有统一结论,按照场景具体分析吧。
回到开始的问题,默认 Exchange 到底特殊在哪里?
官网给出了解释 https://www.rabbitmq.com/tutorials/amqp-concepts.html
The default exchange is a direct exchange with no name (empty string) pre-declared by the broker. It has one special property that makes it very useful for simple applications: every queue that is created is automatically bound to it with a routing key which is the same as the queue name.
每个队列都自动绑定到默认 Exchange,绑定键为队列名称。就这么简单粗暴!
RabbitMQ入门_04_Exchange & Binding的更多相关文章
- RabbitMQ入门与使用篇
介绍 RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue)协议的开源实现.用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面都非常的优秀 ...
- [转]RabbitMQ入门教程(概念,应用场景,安装,使用)
原文地址:https://www.jianshu.com/p/dae5bbed39b1 RabbitMQ 简介 RabbitMQ是一个在AMQP(Advanced Message Queuing Pr ...
- RabbitMQ入门:主题路由器(Topic Exchange)
上一篇博文中,我们使用direct exchange 代替了fanout exchange,这次我们来看下topic exchange. 一.Topic Exchange介绍 topic exchan ...
- RabbitMQ入门:路由(Routing)
在上一篇博客<RabbitMQ入门:发布/订阅(Publish/Subscribe)>中,我们认识了fanout类型的exchange,它是一种通过广播方式发送消息的路由器,所有和exch ...
- RabbitMQ入门:发布/订阅(Publish/Subscribe)
在前面的两篇博客中 RabbitMQ入门:Hello RabbitMQ 代码实例 RabbitMQ入门:工作队列(Work Queue) 遇到的实例都是一个消息只发送给一个消费者(工作者),他们的消息 ...
- RabbitMQ入门(3)——发布/订阅(Publish/Subscribe)
在上一篇RabbitMQ入门(2)--工作队列中,有一个默认的前提:每个任务都只发送到一个工作人员.这一篇将介绍发送一个消息到多个消费者.这种模式称为发布/订阅(Publish/Subscribe). ...
- .NET 环境中使用RabbitMQ RabbitMQ与Redis队列对比 RabbitMQ入门与使用篇
.NET 环境中使用RabbitMQ 在企业应用系统领域,会面对不同系统之间的通信.集成与整合,尤其当面临异构系统时,这种分布式的调用与通信变得越发重要.其次,系统中一般会有很多对实时性要求不高的 ...
- RabbitMQ入门教程(十六):RabbitMQ与Spring集成
原文:RabbitMQ入门教程(十六):RabbitMQ与Spring集成 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...
- RabbitMQ入门教程(二):简介和基本概念
原文:RabbitMQ入门教程(二):简介和基本概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn ...
随机推荐
- springmvc学习笔记一框架的理解
SpringMVC现在在很多公司都很流行,所以这个框架对我们来说,是很重要的. 首先我们对比mvc来分析springmvc这个框架是怎么设计,以及它的工作的流程. 首先来看mvc: 1. 用户发起r ...
- Javascript-逻辑或(||)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Fenwick
hdu1394 这题说的是给了一个序列计算这个序列的逆序对总共要进行n次 每次都将目前的第一个放到序列的最后一个位置然后 计算一次逆序对 这样我们只需要先求一次逆序对 然后接着每次都用F=F+(n-T ...
- Linux服务器---apache支持SSL
Apache支持ssl 1.检测是否安装ssl模块,如果没有就安装 [root@localhost cgi-bin]# rpm -qa | grep mod_ssl //查看是否安 ...
- centos 安装sftp服务
打开命令终端窗口,按以下步骤操作. 0.查看openssh的版本 ssh -V 使用ssh -V 命令来查看openssh的版本,版本必须大于4.8p1,低于的这个版本需要升级. 1.创建sftp组 ...
- iOS开发之AFNetworking实现数据传输和文件上传
//传输数据 1 AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.r ...
- P2158/bzoj2190 [SDOI2008]仪仗队
P2158 [SDOI2008]仪仗队 欧拉函数 计算下三角的点数再*2+1 观察斜率,自行体会 #include<iostream> #include<cstdio> #in ...
- 20145324王嘉澜 《网络对抗技术》 MAL_逆向与Bof基础
实践目标 •本次实践的对象是一个名为pwn1的linux可执行文件. •该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. •该程序同时包含另一个代码片段,get ...
- Win32 实现 MFC CFileDialog 对话框
void CWriteWnd::OpenFileDialog() { OPENFILENAME ofn; TCHAR szFile[MAX_PATH] = _T(""); Zero ...
- jQuery 源码分析:当 selector 传来一个函数时,怎么进行处理?
本文章为 0.9 版本,将会在稍后润色更新.本文使用的 jQuery 版本为 3.4.0 我们知道使用 $ 操作符时,可以往里面塞很多类型的参数,字符串,对象,函数...,jQuery 会根据不同的参 ...