目录

RabbitMQ学习总结 第一篇:理论篇
RabbitMQ学习总结 第二篇:快速入门HelloWorld

RabbitMQ学习总结 第三篇:工作队列Work Queue

RabbitMQ学习总结 第四篇:发布/订阅 Publish/Subscribe

RabbitMQ学习总结 第五篇:路由Routing

RabbitMQ学习总结 第六篇:Topic类型的exchange

RabbitMQ学习总结 第七篇:RCP(远程过程调用协议)

上一篇中我们构建了一个简单的日志系统,我们可以把日志消息广播给多个接受者。

这篇中我们将来添加一个特性只接收部分消息。例如我只将一些错误log存到文件中,把所有的log都打印到控制台里。

1、绑定(Bindings)

在上篇博文中,我们已经创建了一个binding,代码如下:

channel.queueBind(queueName, EXCHANGE_NAME, "");

一个binding就是exchange和Queue之间的一个关系。可以简单的理解为:这个Queue对其相对于的exchange的消息感兴趣(原文是the queue is interested in messages from this exchange,能理解什么意思,但总觉得怪怪的)。

Binding可以使用一个已经存在的routingKey参数。为了避免和basic_publish参数混淆,我们称之为binding key。下边就是我们怎么用key来创建一个binding:

channel.queueBind(queueName, EXCHANGE_NAME, "black");

binding key的意义有时候取决于exchange的类型。对于Fanout类型的exchange,会忽略binding key。

2、Direct类型的exchange

我们上篇博文中的日志系统会把所有的log消息广播给所有的消费者。我们想扩展来根据他们的日志级别来过滤log消息。例如:我们只想把error级别的日志写到磁盘文件中,而其它级别的日志消息则过滤掉。

我们之前使用的fanout类型的exchange,但这样就不会有太多的灵活性。

在这里我们将要使用direct类型的exchange。Direct类型exchange的路由算法是很简单的:要想一个消息能到达这个队列,需要binding key和routing key正好能匹配得上。

为了说明这个道理,可以看看下边的描述:

在这样的结构中,我们可以看到direct类型的exchange X,有两个queue绑定到它。第一个queue是以orange为binding key绑定到exchange X上的,第二个queue是由两个binding key(black和green)绑定到exchange X的。

在这样的设置中,一条消息被推送到exchange,如果使用的routing key是orange,那么消息就会被路由到Q1中;如果使用的routing key是black或green,那么该消息将会被路由到Q2中。其它的消息都将会被丢弃掉。

3、多重绑定(Multiple bindings)

用同一个binding来把多个queue绑定到同一个exchange也是可行的。例如在之前例子的基础上,在X和Q1之间添加binding key名字为black,这样的话,这里的direct类型的exchange就和fanout类型的一样了,可以把消息推送给所有的queue。带有routing key为black的消息将会被推送到Q1和Q2中。

4、发送日志(Emitting logs)

我们将会使用这种模型,不使用fanout类型的exchange,而是使用direct类型的。我们使用日志级别做为routing key,接收端根据设置的日志级别做为binding key来接收消息。首先来看看发射日志:

如之前一样,首先来创建一个exchange:

channel.exchangeDeclare(EXCHANGE_NAME, "direct");

然后准备发送消息;

channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());

这里的”severity”可以是”info”、“warning”、”error”等。

5、订阅(Subscribing)

这里接收消息和上篇博文中的一样,只是有一点例外:我们将会为每一个感兴趣的日志级别进行绑定。

String queueName = channel.queueDeclare().getQueue();

for(String severity : argv){
channel.queueBind(queueName, EXCHANGE_NAME, severity);
}

6、最终实现

  • EmitLogDirect.java的代码:
public class EmitLogDirect {
private static final String EXCHANGE_NAME = "direct_logs";
public static void main(String[] argv)
throws java.io.IOException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel(); //声明direct类型的exchange
channel.exchangeDeclare(EXCHANGE_NAME, "direct");

    //拿到日志级别
String severity = getSeverity(argv); //拿到日志消息
String message = getMessage(argv); //指定routing key,发送消息
channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
System.out.println(" [x] Sent '" + severity + "':'" + message + "'");
channel.close();
connection.close();
}
//..
}
  • ReceiveLogsDirect.java的代码:
public class ReceiveLogsDirect {
private static final String EXCHANGE_NAME = "direct_logs";
public static void main(String[] argv)
throws java.io.IOException,
java.lang.InterruptedException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel(); //声明direct类型的exchange
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
String queueName = channel.queueDeclare().getQueue(); if (argv.length < ){
System.err.println("Usage: ReceiveLogsDirect [info] [warning] [error]");
System.exit();
} //绑定我们需要接收的日志级别
for(String severity : argv){
channel.queueBind(queueName, EXCHANGE_NAME, severity);
} System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, consumer); while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
String routingKey = delivery.getEnvelope().getRoutingKey(); System.out.println(" [x] Received '" + routingKey + "':'" + message + "'");
}
}
}
  • 运行三个日志接收器:

接收error和info级别的日志:

接收error级别的日志:

接收info级别的日志:

  • 运行两个日志发生器:

产生error级别的日志:

产生info级别的日志:

  • 观察接收器端的变化:

接收error级别的接收器,只接收error级别的日志:

接收info级别的接收器,只接收info级别的日志:

Error和info级别日志都接收的接收器,info和error级别的日志都接收:

7、总结:

要记住生产者端的routing key,那么在消费者端设置binding key和之前的routing key一样,就可以用direct类型的exchange了,以此来获取到自己需要的消息。

参考链接:http://www.rabbitmq.com/tutorials/tutorial-four-java.html

RabbitMQ学习总结 第五篇:路由Routing的更多相关文章

  1. Rabbitmq消息队列(五) 路由Routing

    1.简介 在以前一章中,我们可以把一个消息广播给多个接收者.在这一章中,我们会增加一个功能:接收者能够只接收订阅消息中的一个子集. 2.绑定 在我们将交换机和队列进行绑定的时候,我们可以添加一个额外的 ...

  2. RabbitMQ学习总结 第三篇:工作队列Work Queue

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  3. RabbitMQ学习总结 第四篇:发布/订阅 Publish/Subscribe

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  4. RabbitMQ学习总结 第六篇:Topic类型的exchange

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  5. RabbitMQ学习笔记(五) Topic

    更多的问题 Direct Exchange帮助我们解决了分类发布与订阅消息的问题,但是Direct Exchange的问题是,它所使用的routingKey是一个简单字符串,这决定了它只能按照一个条件 ...

  6. Egret入门学习日记 --- 第五篇(书中 3.5节 内容)

    第五篇(书中 3.5节 内容) 今天得把昨天的问题解决了才行. 去了Q群,碰到一位大大,他给我解惑了.Thanks♪(・ω・)ノ 这是我之前按照书上写的方式写的,并没有效果. 然后大大给我解答了: 后 ...

  7. 【c#】RabbitMQ学习文档(四)Routing(路由)

    (使用Net客户端) 在上一个教程中,我们构建了一个简单的日志系统,我们能够向许多消息接受者广播发送日志消息. 在本教程中,我们将为其添加一项功能 ,这个功能是我们将只订阅消息的一个子集成为可能. 例 ...

  8. RabbitMQ消息队列(五):Routing 消息路由[转]

    上篇文章中,我们构建了一个简单的日志系统.接下来,我们将丰富它:能够使用不同的severity(严重程度)来监听不同等级的log.比如我们希望只有error的log才保存到磁盘上. 1. Bindin ...

  9. RabbitMQ消息队列(五):Routing 消息路由

        上篇文章中,我们构建了一个简单的日志系统.接下来,我们将丰富它:能够使用不同的severity来监听不同等级的log.比如我们希望只有error的log才保存到磁盘上. 1. Bindings ...

随机推荐

  1. android之TabHost(下)

    首先建立res/layout/tab.xml文件 编写代码如下: <?xml version="1.0" encoding="utf-8"?> &l ...

  2. OS | 读写锁【摘】

    读写锁是用来解决读者写者问题的,读操作可以共享,写操作是排他的,读可以有多个在读,写只有唯一个在写,同时写的时候不允许读. 互斥锁与读写锁的区别: 当访问临界区资源时(访问的含义包括所有的操作:读和写 ...

  3. 【转】各版本IIS下ASP.net请求处理过程区别

    原文地址:http://www.cnblogs.com/fsjohnhuang/articles/2332074.html ASP.NET是一个非常强大的构建Web应用的平台,它提供了极大的灵活性和能 ...

  4. Bootstrap页面布局8 - BS常用标签与样式

    常用的Css文字标签 一. <p>文字段落Start,<strong>重要的文字</strong>,<em>倾斜的文字用来提示</em>,& ...

  5. 批量更改int类型的timestamp字段to datetime

    批量更改int类型的timestamp字段to datetime 1.创建datetime字段created_at 2.update 字段 UPDATE table set created_at = ...

  6. Java单链表的实现

    将结点Node进行封装,假设Node的操作有增加,删除,查找,打印几个操作.将Node实现为链表Link的内部类,简化代码. package Chapter5; import java.securit ...

  7. java获取类路径

    String file = MessageTask3.class.getResource("").getFile(); File: public static final Stri ...

  8. 下面我会介绍几种轻轻松松访问Google的方法

    好人一生平安的大招 Google在大陆已经封了差不多有20天   访问是极其的困难 下面我会介绍几种轻轻松松访问Google的方法 首先 你需要个可靠的hosts  比如 https://git.os ...

  9. android 定位的四种方式

    [原文]  开发中对于地图及地理位置的定位是我们经常要用地,地图功能的使用使得我们应用功能更加完善,下面总结了一下网络中现有对于介绍android定位的4种方式,希望对大家有帮助: android 定 ...

  10. ubuntu下c/c++开发环境配置

    刚转好的UBUNTU14.04.01 TLS . 试了一下GCC,结果如下不能编译 gcc -o hello hello.cpp gcc: error trying to exec 'cc1plus' ...