RabbitMQ指南之四:路由(Routing)和直连交换机(Direct Exchange)
在上一章中,我们构建了一个简单的日志系统,我们可以把消息广播给很多的消费者。在本章中我们将增加一个特性:我们可以订阅这些信息中的一些信息。例如,我们希望只将error级别的错误存储到硬盘中,同时可以将所有级别(error、info、warning等)的日志都打印在控制台上。
1、绑定(Bindings)
在上一章中,我们已经创建了绑定关系,回顾一下代码:
channel.queueBind(queueName, EXCHANGE_NAME, "");
一个绑定是一个交换器与队列之间的关系。意思是指:这个队列对这个交换器的消息感兴趣。
该方法同时还有另一个routing Key参数,为了避免与basic_public参数产生中的路由键(routing key)混淆,我们称之为绑定键(bingind key),下面展示了如何通过一个绑定key创建一个绑定:
channel.queueBind(queueName, EXCHANGE_NAME, "black");
注意,这个绑定键(这里是"black")的含义依赖于交换器的类型。比如在我们的日志系统中,交换器类型为fanout,此时,绑定键没有任何意义,会被忽略掉。
2、直连交换机(Direct Exchange)
在我们之前的日志系统中,所有的消息被广播给所有的消费者,但是本章的需要是希望有一个程序可以只接收error级别的日志并保存到磁盘中,而不用浪费空间去存储那些info、warning级别的日志。
我们正在用的广播模式的交换器并不够灵活,它只是不加思索地进行广播。因此,需要使用direct exchange来代替。直连交换器的路由算法非常简单:将消息推送到binding key与该消息的routing key相同的队列。
为了说明这点,请看下图:
在该图中,直连交换器X上绑定了两个队列。第一个队列绑定了绑定键orange,第二个队列有两个绑定键:black和green。在这种场景下,一个消息在布时指定了路由键为orange将会只被路由到队列Q1,路由键为black和green的消息都将被路由到队列Q2。其他的消息都将被丢失。
3、多重绑定
同一个绑定键可以绑定到不同的队列上去,在上图中,我们也可以增加一个交换器X与队列Q2的绑定键,在这种情况下,直连交换器将会和广播交换器有着相同的行为,将消息推送到所有匹配的队列。一个路由键为black的消息将会同时被推送到队列Q1和Q2。
4、发送日志
首先我们要一如既往地创建一个交换器:
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
并准备发送消息:
channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
我们需要确保在我们日志系统中参数"severity"是“info”、“warning”和“error”中的一个。
5、订阅
创建接收消息与上一章基本相同,唯一不同的是,需要在创建绑定关系时,指定severity的值:
String queueName = channel.queueDeclare().getQueue(); for(String severity : argv){
channel.queueBind(queueName, EXCHANGE_NAME, severity);
}
6、完整的代码
EmitLogDirect.java
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory; public class EmitLogDirect { private static final String EXCHANGE_NAME = "direct_logs"; public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.exchangeDeclare(EXCHANGE_NAME, "direct"); String severity = getSeverity(argv);
String message = getMessage(argv); channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + severity + "':'" + message + "'");
}
}
//..
}
ReceiveLogsDirect.java
import com.rabbitmq.client.*; public class ReceiveLogsDirect { private static final String EXCHANGE_NAME = "direct_logs"; public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME, "direct");
String queueName = channel.queueDeclare().getQueue(); if (argv.length < 1) {
System.err.println("Usage: ReceiveLogsDirect [info] [warning] [error]");
System.exit(1);
} for (String severity : argv) {
channel.queueBind(queueName, EXCHANGE_NAME, severity);
}
System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" +
delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
};
channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });
}
}
为了测试方便,我们可以把"info"、"error"、"warning"都绑定到一个队列上去,然后生产者分别往"info"、"error"、"warning"发送消息:
此时查看RabbitMq控制台:
到此,发布-订阅涉及到的相关知识点都讲解完了,下一章将讲解Topic(主题模式)。
RabbitMQ指南之四:路由(Routing)和直连交换机(Direct Exchange)的更多相关文章
- RabbitMQ入门:路由(Routing)
在上一篇博客<RabbitMQ入门:发布/订阅(Publish/Subscribe)>中,我们认识了fanout类型的exchange,它是一种通过广播方式发送消息的路由器,所有和exch ...
- RabbitMQ入门(4)——路由(Routing)
这一篇我们将介绍如何订阅消息的一个子集.例如,我们只需要将日志中的error消息存储到日志文件中而将所有日志消息都在控制台打印出来. 绑定(Bindings) 在前面的例子中,我们创建了交换机和队列的 ...
- Rabbit的直连交换机direct
直连交换机类型为:direct.加入了路由键routingKey的概念. 就是说 生产者投递消息给指定交换机的指定路由键. 只有绑定了此交换机指定路由键的消息队列才可以收到消息. 生产者: packa ...
- PHP 下基于 php-amqp 扩展的 RabbitMQ 简单用例 (一) -- 安装 AMQP 扩展和 Direct Exchange 模式
Windows 安装 amqp 扩展 RabbitMQ 是基于 amqp(高级消息队列协议) 协议的.使用 RabbitMQ 前必须为 PHP 安装相应的 amqp 扩展. 下载相应版本的 amqp ...
- RabbitMQ --- 直连交换机 【 有回调方法,获取消费结果 】
1.前言 上一随笔详细记录了直连交换机的方法,发送的消息是异步的,如果消息未被消费者消费,那么可以一直存在消息队列中. 那么有没有办法做一个回调,当消息被消费后,被通知消息成功被消费者消费啦? 答案是 ...
- RabbitMQ --- 直连交换机 【 无回调方法,不能获取消费结果 】
1.前言 消息队列除了kafka 外,还有许多种,比如RabbitMQ .ActiveMQ.ZeroMQ.JMQ等. 老牌的ActiveMQ ,底层使用Java写的,资源消耗大,速度也慢,但是适合 J ...
- spring boot 集成 rabbitmq 指南
先决条件 rabbitmq server 安装参考 一个添加了 web 依赖的 spring boot 项目 我的版本是 2.5.2 添加 maven 依赖 <dependency> &l ...
- RabbitMQ入门教程——路由(Routing)
绑定( Bindings) 之前的文章中我们已经创建过bindings,代码如下: channel.QueueBind(queue: queueName, exchange: EX ...
- RabbitMQ官方中文入门教程(PHP版) 第四部分:路由(Routing)
路由(Routing) 在前面的教程中,我们实现了一个简单的日志系统.可以把日志消息广播给多个接收者. 本篇教程中我们打算新增一个功能——使得它能够只订阅消息的一个字集.例如,我们只需要把严重的错误日 ...
随机推荐
- 2017-10-03-afternoon
P100 zhx 竞赛时间:????年??月??日??:??-??:?? 题目名称 a b c 名称 a b c 输入 a.in b.in c.in 输出 a.out b.out c.out 每个测试 ...
- 2017-10-02-afternoon
T1 最大值(max) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一本书,上面有很多有趣的OI问题.今天LYK看到了这么一道题目: 这里有一个长度 ...
- Ubuntu 16.04下减小/释放/清理VirtualBox虚拟硬盘文件的大小
一般在VirtualBox中安装Windows,然后用无缝模式进行某些特定软件的使用. 而VirtualBox的虚拟硬盘会越用越大,并且VirtualBox没有自带清理工具,相比VMware来说,VM ...
- MySQL主主复制搭建教程收集(待实践)
先收集,后续再实践. http://www.cnblogs.com/ahaii/p/6307648.html http://blog.csdn.net/jenminzhang/article/deta ...
- JSP的客户端请求
以下内容引用自http://wiki.jikexueyuan.com/project/jsp/client-request.html: 当浏览器请求一个网页时,它向Web服务器发送大量的信息,信息不能 ...
- SaltStack及Multi-Master介绍
1.先说下SaltStack是啥? SaltStack是基于Python开发的一套C/S架构配置管理工具(功能不仅仅是配置管理,如使用salt-cloud配置AWS EC2实例),它的底层使用Zero ...
- docker: 通过docker方式安装jenkins
1. docker pull jenkins 2. docker run -d -p 49001:8080 -v $PWD/jenkins:/var/jenkins_home:z -t jenkins ...
- 关于Windows 8使用WMP播放音乐时WUDFHost跑CPU和硬盘的问题解决
Windows 8使用Windows Media Player播放音乐的时候.事实上有一个这种情况,WMP和某个什么名字看起来非常屌的进程跑CPU非常高,这个跑非常高视你插入的SD卡内的文件数或者移动 ...
- php把时间计算成几分钟前,几小时前,几天前的函数
function time_tran($the_time){ $now_time = date("Y-m-d H:i:s",time()+8*60*60); $now_time = ...
- Java 编码 UTF-8
近期在处理文件时发现了相同类型的文件使用的编码可能是不同的.所以想将文件的格式统一一下(由于UTF-8的通用性,决定往UTF-8统一),遇见的第一个问题是:怎样查看现有文件的编码方式. 文件编码问题集 ...