上篇文章中,我们构建了一个简单的日志系统。接下来,我们将丰富它:能够使用不同的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. 如何使用Windows Library文件进行持久化

    前言 想象一下,假设在你不知道的情况下,攻击者在你的计算机上放置了一个恶意文件.每当你访问桌面上某个文件夹时(例如Documents文件夹),都会执行一次该文件.这样的场景,通过利用一种鲜为人知的持久 ...

  2. 用VLC读取摄像头产生RTSP流,DSS主动取流转发(一)(二) 【转】

    http://blog.csdn.net/fm0517/article/details/38110633 http://blog.csdn.net/fm0517/article/details/381 ...

  3. 内存泄漏 Memory Leaks 内存优化 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  4. Raphael path 拖动实现

    让 Raphael 的 Path 动起来 Raphaël 是一个很实用的线上矢量图操作 Javascript 库.使用简单,一个值得一提的卖点是通过抽象出共同的接口屏蔽了 SVG 和 VML 之间的差 ...

  5. C# 的三种序列化方法

    序列化是将一个对象转换成字节流以达到将其长期保存在内存.数据库或文件中的处理过程.它的主要目的是保存对象的状态以便以后需要的时候使用.与其相反的过程叫做反序列化. 序列化一个对象 为了序列化一个对象, ...

  6. UICamera(NGUI Event system)原理

    看了UICamera的源码就显而易见了: UICamera « on: November 21, 2013, 12:21:48 AM »   Overview UICamera is a somewh ...

  7. DockerHub基于Github自己主动化构建

    Docker Hub上的自己主动化构建 关于自己主动化构建 自己主动化构建是一个特殊的功能,它同意您在 Docker Hub 上使用构建集群,依据指定的 Dockerfile 或者 GitHub . ...

  8. windows server 2012 IE增强的安全配置如何关闭

    http://jingyan.baidu.com/article/6181c3e076ac0b152ff15354.html 打开左下角的 服务端 关闭这个就可以了

  9. ios backgroundColor

    loginView.backgroundColor=[UIColorcolorWithHue:0saturation:0brightness:0.9alpha:0.85]; 可随意调

  10. __inline定义的内联函数和宏的区别

    转自:http://blog.csdn.net/lw370481/article/details/7311668 函数与宏 #define TABLE_COMP(x) ((x)>0?(x):0) ...