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

1. Bindings绑定

上篇文章中我们是这么做的绑定:

channel.QueueBind(queueName, EXCHANGE_NAME, ROUTING_KEY);//const string ROUTING_KEY = "";

绑定其实就是关联了exchange和queue。或者这么说:queue对exchange的内容感兴趣,exchange要把它的Message deliver(提供)到queue中。

实际上,绑定可以带routing key这个参数,空字符串也是一个routing key的名字。其实这个参数的名称和basic_publish的参数名是相同了。第二篇有介绍当exchange的名称为空字符串的时候,创建queue的时候用到queue的名字和Producer的BasicPublish方法或Consuner的BasicConsume方法的routing key的名字可以是相同的。即queue的名字和routing key的名字是相同的。

为了避免混淆,我们把这个routing key称为binding key(即在Exchange中的routing key)

使用一个binding key来创建binding :

channel.QueueBind(queueName, EXCHANGE_NAME, routingKey);//string routingKey = "指定RoutingKey的名称";

上一篇文章我们讲的是使用fanout类型的exchange,对于fanout的exchange来说,这个参数是被忽略的。

2. Direct exchange

Direct exchange的路由算法非常简单:通过binding key的完全匹配,可以通过下图来说明。


    exchange X和两个queue绑定在一起。Q1的binding key是orange。Q2的binding key是black和green。
    当P发布的key是orange时,exchange会把它放到Q1。如果P发布的key是black或者green那么就会到Q2。其余的Message都会被丢弃。本篇最后面(queue的名字是rabbitmq自己起的)和下一篇第一个例子(queue的名字是程序指定的)就是实现这上面这副图的代码——将多个routing key(或者称为binding key)绑定到同一个名称的queue。

3. Multiple bindings

      多个queue绑定同一个key是可以的。对于下图的例子,Q1和Q2都绑定了black。也就是说,对于routing key是black的Message,会被deliver(提供)到Q1和Q2。其余的Message都会被丢弃。下一篇第二个例子就是讲这副图的例子,将同一个routing key(或者binding key)绑定到多个不同名称的queue上。
 

4. Emitting logs

首先是我们要创建一个direct的exchange:

const string EXCHANGE_NAME = "direct_logs";
channel.ExchangeDeclare(EXCHANGE_NAME, "direct");

我们将使用log的severity(严重级别)作为routing key,这样Consumer可以针对不同severity(严重级别)的log进行不同的处理。

channel.BasicPublish(EXCHANGE_NAME, routingKey, null, body);

我们使用三种severity(严重级别):'info', 'warning', 'error'.

5. Subscribing

对于queue,我们需要绑定severity(严重级别):

const string EXCHANGE_NAME = "direct_logs";
channel.ExchangeDeclare(EXCHANGE_NAME, "direct");
string queueName = channel.QueueDeclare(); channel.QueueBind(queueName, EXCHANGE_NAME, routingKey);

6. 最终版本

本例子是没有指定Queue的名称:
Producer.cs
  /// <summary>
/// 多个routing key指定同一个queue
/// 接收端创建临时queue
/// </summary>
/// <param name="args">
/// SendDemo5.exe direct_custom_routing_key_hello1
/// SendDemo5.exe direct_custom_routing_key_hello2
/// </param>
static void Main(string[] args)
{
if (args.Length < )
{
Console.Error.WriteLine("请指定一个新的Routing Key名称", Environment.GetCommandLineArgs()[]);
Environment.ExitCode = ;
return;
}
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
const string EXCHANGE_NAME = "direct_logs";
channel.ExchangeDeclare(EXCHANGE_NAME, "direct");//Direct :如果 routing key 匹配, 那么Message就会被传递到相应的queue中。
//Exchange在queue创建时,它会自动的以queue的名字作为routing key来绑定那个exchange。
var routingKey = args[];
var message = "Hello World!";
var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(EXCHANGE_NAME, routingKey, null, body);
Console.WriteLine(" [x] Sent '{0}':'{1}'", routingKey, message);
}
}
}

Producer.cs

Consumer.cs

 /// <summary>
/// 多个routing key指定同一个queue
/// 接收端创建临时queue
/// </summary>
/// <param name="args">
/// ReceiveDemo5.exe direct_custom_routing_key_hello1
/// ReceiveDemo5.exe direct_custom_routing_key_hello2
/// </param>
static void Main(string[] args)
{
if (args.Length < )
{
Console.Error.WriteLine("请指定一个新的Routing Key名称", Environment.GetCommandLineArgs()[]);
Environment.ExitCode = ;
return;
}
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
const string EXCHANGE_NAME = "direct_logs";
channel.ExchangeDeclare(EXCHANGE_NAME, "direct");//接收端如果关闭之后,自动创建的Queue会自动被删除
string queueName = channel.QueueDeclare();//获取临时创建的Queue的名称 foreach (var routingKey in args)
{
channel.QueueBind(queueName, EXCHANGE_NAME, routingKey);
} Console.WriteLine(" [*] Waiting for messages. " + "To exit press CTRL+C"); var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume(queueName, true, consumer); while (true)
{
var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue(); var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
var routingKey = ea.RoutingKey;
Console.WriteLine(" [x] Received '{0}':'{1}'", routingKey, message);
}
}
}
}

Consumer.cs

必须先运行Consumer,然后在运行Producer.

转:
http://www.rabbitmq.com/tutorials/tutorial-four-dotnet.html(官网)
http://blog.csdn.net/anzhsoft/article/details/19630147(翻译)

RabbitMQ消息队列(五):Routing 消息路由[转]的更多相关文章

  1. 消息队列之事务消息,RocketMQ 和 Kafka 是如何做的?

    每个时代,都不会亏待会学习的人. 大家好,我是 yes. 今天我们来谈一谈消息队列的事务消息,一说起事务相信大家都不陌生,脑海里蹦出来的就是 ACID. 通常我们理解的事务就是为了一些更新操作要么都成 ...

  2. 几种MQ消息队列对比与消息队列之间的通信问题

    消息队列 开发语言 协议支持 设计模式 持久化支持 事务支持 负载均衡支持 功能特点 缺点 RabbitMQ Erlang AMQP,XMPP,SMTP,STOMP 代理(Broker)模式(消息在发 ...

  3. 译:4.RabbitMQ Java Client 之 Routing(路由)

    在上篇博文 译:3.RabbitMQ 之Publish/Subscribe(发布和订阅)  我们构建了一个简单的日志系统 我们能够向许多接收者广播日志消息. 在本篇博文中,我们将为其添加一个功能 - ...

  4. 分布式消息队列RocketMQ--事务消息--解决分布式事务

    说到分布式事务,就会谈到那个经典的”账号转账”问题:2个账号,分布处于2个不同的DB,或者说2个不同的子系统里面,A要扣钱,B要加钱,如何保证原子性? 一般的思路都是通过消息中间件来实现“最终一致性” ...

  5. Java使用Rabbitmq惊喜队列queue和消息内容的本地持久化核心方法。(内容存储在硬盘)

    _Channel.queueDeclare(queue, true, false, false, null); _Channel.basicPublish(_ExchangeName, queue,M ...

  6. 分布式消息队列RocketMQ&Kafka -- 消息的“顺序消费”

    在说到消息中间件的时候,我们通常都会谈到一个特性:消息的顺序消费问题.这个问题看起来很简单:Producer发送消息1, 2, 3... Consumer按1, 2, 3...顺序消费. 但实际情况却 ...

  7. C#消息队列(RabbitMQ)零基础从入门到实战演练

    一.课程介绍 如果您从工作中之听过但未有接触过消息对队列(MQ),如果你接触过一点关于MQ的知识,如果没有这么的多如果的话......,那么阿笨将通过本次<C#消息队列零基础从入门到实战演练&g ...

  8. RabbitMQ消息队列应用

    RabbitMQ消息队列应用 消息通信组件Net分布式系统的核心中间件之一,应用与系统高并发,各个组件之间解耦的依赖的场景.本框架采用消息队列中间件主要应用于两方面:一是解决部分高并发的业务处理:二是 ...

  9. RabbitMQ 消息队列 二

    一:查看MQ的用户角色 rabbitmqctl list_users 二:添加新的角色,并授予权限 rabbitmqctl add_user xiaoyao 123456 rabbitmqctl se ...

  10. RabbitMQ,Apache的ActiveMQ,阿里RocketMQ,Kafka,ZeroMQ,MetaMQ,Redis也可实现消息队列,RabbitMQ的应用场景以及基本原理介绍,RabbitMQ基础知识详解,RabbitMQ布曙

    消息队列及常见消息队列介绍 2017-10-10 09:35操作系统/客户端/人脸识别 一.消息队列(MQ)概述 消息队列(Message Queue),是分布式系统中重要的组件,其通用的使用场景可以 ...

随机推荐

  1. 数据库实例: STOREBOOK > 用户 > 编辑 用户: MGMT_VIEW

    ylbtech-Oracle:数据库实例: STOREBOOK  >  用户  >  编辑 用户: MGMT_VIEW 编辑 用户: MGMT_VIEW 1. 一般信息返回顶部 1.1, ...

  2. C#中的集合(HashTable与Array类)

    一.Array类 1.Array类的属性 序号 属性 & 描述 1 IsFixedSize 获取一个值,该值指示数组是否带有固定大小. 2 IsReadOnly 获取一个值,该值指示数组是否只 ...

  3. 关于DLL文件和EXE文件不在同一目录下的设置【转】

    https://www.cnblogs.com/chaosimple/archive/2012/08/13/2636181.html 关于DLL文件和EXE文件不在同一目录下的设置 在开发程序结束后, ...

  4. php解决乱码问题时,出现Cannot modify header information问题的解决方法

    设置页面编码使用: header("Content-Type:text/html;charset=utf-8"); 会出现:Cannot modify header informa ...

  5. C/C++语言中变量作用域:局部变量,全局变量,文件级变量

    C/C++语言中的变量分为全局变量和局部变量. 这样的划分方式的根据是变量的可见范围或者叫做作用域. 1 局部变量 局部变量指的是定义在{}中的变量,其作用域也在这个范围内.尽管常见的局部变量都是定义 ...

  6. GO语言基础语法

    1. Go项目的目录结构 一般的,一个Go项目在GOPATH下,会有如下三个目录: project   --- bin   --- pkg   --- src 其中,bin 存放编译后的可执行文件:p ...

  7. 如何使用动画和精灵表单 Cocos2d-x 2.1.4

            本文实践自 Ray Wenderlich.Tony Dahbura 的文章< How to Use Animations and Sprite Sheets in Cocos2D ...

  8. 30款免费的手机UI设计资源

    在 原型设计阶段,我们会尽量寻找一些灵感刺激大脑,从而让我们的想象力飞-灵感给了我们很好的开始,但是当我们把灵感化为现实的时候,又需要一些实用而又高 效的组件来完成.即使你有非常善于把灵感实例化在草稿 ...

  9. 多个桌面Deskspace如何使用

    1 给Deskspace设置背景.在DeskSpace选项中设置显示背景为天空箱体图像(软件自带的图像效果,也可以使用静态图像,即自己的图片) 2 给六个桌面各设置一个背景(也可以使用同一个背景)右击 ...

  10. ifconf和ifreq

    http://blog.csdn.net/jasenwan88/article/details/7763689 用ioctl获得本地ip地址时要用到两个结构体ifconf和ifreq,它们对于大多数人 ...