在上一篇中使用直接交换器改进了我们的系统,使得它能够有选择的进行接收消息,但它仍然有局限性——它不能基于多个条件进行路由。本节我们就进行能够基于多个条件进行路由的topics exchange学习。

发送给主题交换器的消息不能是任意的routing_key—它必须是一个单词列表,由点分隔。这些词可以是任意的,但通常它们指定与消息相关的一些特性。几个有效的路由示例:"stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit".。路由键中可以有任意多的字,最多可以有255个字节。

路由键也需要是相同的形式,topic交换器背后的逻辑类似于direct交换器——发送带有特定路由键的消息将被传送到绑定匹配路由键的所有队列中,

然而,有两个重要的特殊情况需要绑定键:

  • * (star) can substitute for exactly one word.                     星号可以代替一个词
  • # (hash) can substitute for zero or more words.               哈希可以代替零个或多个词
  • 通过下面的例子进行解释:
  • 在这个例子中,我们将发送所有描述动物的信息。消息将通过一个包含三个单词(两个点)的路由键发送。路径键中的第一个词将描述速度,第二个是颜色,第三个是物种:“<速度>.<颜色>.<物种>”。
  • We created three bindings: Q1 is bound with binding key "*.orange.*" and Q2 with "*.*.rabbit" and "lazy.#".

    These bindings can be summarised as:

  • Q1对所有的橙色动物都感兴趣。

  • Q2希望听到关于兔子的一切,以及关于懒惰动物的一切。

  • 设置了路由键为 "quick.orange.rabbit"的消息将被投递到两个队列,消息 "lazy.orange.elephant" 也被投递到他们两个,而"quick.orange.fox"将被投递到第一个队列,"lazy.brown.fox"仅被投递到第二个队列,"quick.brown.fox"没有匹配将被舍弃。

  • 通过上面的学习,我们知道,topic主题的交换器投递消息与redict交换器的不同在于,交换器类型和路由键的模糊匹配,现在我们就去把之前的代码进行改变,只需要将代码中的交换器类型改为topic,并将绑定的路由键更改一下,投递消息用的是确定的路由键,接收消息通过设置匹配的模糊绑定键,可以订阅到多条件的消息,接下来上代码,并将改动的代码以下划线形式标记出来。

  • 发送方代码:

  • package com.rabbitmq.HelloWorld;
    
    import java.io.IOException;
    import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.ConnectionFactory; public class Publish { private static final String EXCHANGE_NAME = "exchangeC"; public static void main(String[] args) throws IOException, TimeoutException {
    // TODO Auto-generated method stub
    // 创建工厂
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost("192.168.10.185");
    factory.setUsername("admin");
    factory.setPassword("123456");
    factory.setPort(5672);
    // 创建连接
    Connection connetion = factory.newConnection();
    // 获得信道
    Channel channel = connetion.createChannel();
    // 声明交换器(声明了一个名字位exchangeA,类型修改fanout为direct类型的交换器)
    channel.exchangeDeclare(EXCHANGE_NAME, "topic");
    String message = "555,2,2,33,66";
    // 发送消息,将第二项参数routingkey
    channel.basicPublish(EXCHANGE_NAME, "my.hello.haha", null, message.getBytes());
    System.out.println(" [x] Sent '" + message + "'");
    channel.close();
    connetion.close();
    } }
  • 接收方一:

  • package com.rabbitmq.HelloWorld;
    
    import java.io.IOException;
    import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.ConnectionFactory;
    import com.rabbitmq.client.Consumer;
    import com.rabbitmq.client.DefaultConsumer;
    import com.rabbitmq.client.Envelope;
    import com.rabbitmq.client.AMQP.BasicProperties; public class Subscribe { private static final String EXCHANGE_NAME = "exchangeC";
    private static final String QUEUE_NAME = "queueA"; public static void main(String[] args) throws IOException, TimeoutException {
    // TODO Auto-generated method stub
    // 创建工厂
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost("192.168.10.185");
    factory.setUsername("admin");
    factory.setPassword("123456");
    factory.setPort(5672);
    // 创建连接
    Connection connetion = factory.newConnection();
    // 获得信道
    Channel channel = connetion.createChannel();
    // 声明交换器(声明了一个名字位exchangeA,类型修改fanout为direct的交换器)
    channel.exchangeDeclare(EXCHANGE_NAME, "topic");
    // 声明一个队列,在此采用临时队列
    String queueName = channel.queueDeclare().getQueue();
    // channel.queueDeclare(QUEUE_NAME, true, false, false, null);
    // 队列和交换器进行绑定,并设定路由键为error
    channel.queueBind(queueName, EXCHANGE_NAME, "my.#");
    System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
    Consumer consumer = new DefaultConsumer(channel){
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope,
    BasicProperties properties, byte[] body) throws IOException {
    // TODO Auto-generated method stub
    String message = new String(body,"utf-8");
    System.out.println("[x] received'"+message+"'");
    }
    };
    channel.basicConsume(queueName, consumer);
    } }
  • 接收方二:

  • import java.io.IOException;
    import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel;
    import com.rabbitmq.client.Connection;
    import com.rabbitmq.client.ConnectionFactory;
    import com.rabbitmq.client.Consumer;
    import com.rabbitmq.client.DefaultConsumer;
    import com.rabbitmq.client.Envelope;
    import com.rabbitmq.client.AMQP.BasicProperties; public class Subscribe { private static final String EXCHANGE_NAME = "exchangeC";
    private static final String QUEUE_NAME = "queueA"; public static void main(String[] args) throws IOException, TimeoutException {
    // TODO Auto-generated method stub
    // 创建工厂
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost("192.168.10.185");
    factory.setUsername("admin");
    factory.setPassword("123456");
    factory.setPort(5672);
    // 创建连接
    Connection connetion = factory.newConnection();
    // 获得信道
    Channel channel = connetion.createChannel();
    // 声明交换器(声明了一个名字位exchangeA,修改fanout类型为direct类型的交换器�?
    channel.exchangeDeclare(EXCHANGE_NAME, "topic");
    // 声明�?个队列,在此采用临时队列
    String queueName = channel.queueDeclare().getQueue();
    // channel.queueDeclare(QUEUE_NAME, true, false, false, null);
    // 队列和交换器进行绑定,未设定路由键
    channel.queueBind(queueName, EXCHANGE_NAME, "my.hello.*");
    System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
    Consumer consumer = new DefaultConsumer(channel){
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope,
    BasicProperties properties, byte[] body) throws IOException {
    // TODO Auto-generated method stub
    String message = new String(body,"utf-8");
    System.out.println("[x] received'"+message+"'");
    }
    };
    channel.basicConsume(queueName, consumer);
    } }

    运行后,两个接收方均接收道理发送方发送的消息,尽管我们在两个接收方配置的绑定键并不相同,但是其模糊匹配规则均可以匹配到发送方发送消息的路由键,如果有大量接收方,我们就可以通过设置不同的绑定键来有选择的接收较多的消息或者是不接受消息。

官网英文版学习——RabbitMQ学习笔记(七)Topic的更多相关文章

  1. 官网英文版学习——RabbitMQ学习笔记(一)认识RabbitMQ

    鉴于目前中文的RabbitMQ教程很缺,本博主虽然买了一本rabbitMQ的书,遗憾的是该书的代码用的不是java语言,看起来也有些不爽,且网友们不同人学习所写不同,本博主看的有些地方不太理想,为此本 ...

  2. 官网英文版学习——RabbitMQ学习笔记(十)RabbitMQ集群

    在第二节我们进行了RabbitMQ的安装,现在我们就RabbitMQ进行集群的搭建进行学习,参考官网地址是:http://www.rabbitmq.com/clustering.html 首先我们来看 ...

  3. Unity shader 官网文档全方位学习(一)

    转载:https://my.oschina.net/u/138823/blog/181131 摘要: 这篇文章主要介绍Surface Shaders基础及Examples详尽解析 What?? Sha ...

  4. 利用JQ实现的,高仿 彩虹岛官网导航栏(学习HTML过程中的小记录)

    利用JQ实现的,高仿 彩虹岛官网导航栏(学习HTML过程中的小记录)   作者:王可利(Star·星星) 总结: 今天学习的jQ类库的使用,代码重复的比较多需要完善.严格区分大小写,在 $(" ...

  5. 官网英文版学习——RabbitMQ学习笔记(二)RabbitMQ安装

    一.安装RabbitMQ的依赖Erlang 要进行RabbitMQ学习,首先需要进行RabbitMQ服务的安装,安装我们可以根据官网指导进行http://www.rabbitmq.com/downlo ...

  6. 官网英文版学习——RabbitMQ学习笔记(三)Hello World!

    参考http://www.rabbitmq.com/tutorials/tutorial-one-java.html,我们直接上代码,由于我们的RabbitMQ服务是安装在虚拟机上的,具体参考上一节. ...

  7. 官网英文版学习——RabbitMQ学习笔记(八)Remote procedure call (RPC)

    在第四篇学习笔记中,我们学习了如何使用工作队列在多个工作者之间分配耗时的任务.   但是,如果我们需要在远程计算机上运行一个函数并等待结果呢?这是另一回事.这种模式通常称为远程过程调用或RPC.   ...

  8. 官网英文版学习——RabbitMQ学习笔记(五)Publish/Subscribe

    发布/订阅模式:把一个消息发送给多个消费者. 前几篇文章的思想是,我们好像看到了生产者将消息直接发送给queue,然后消费者也从queue中进行消费.其实并非如此,RabbitMQ中的消息传递模型的核 ...

  9. 官网英文版学习——RabbitMQ学习笔记(四)Work queues

    工作队列:把每个任务只发送给一个工作者. 上一篇我们是从一个指定的队列发送接收消息,在本文中,我们将创建一个工作队列,用于在多个工作者之间分配耗时的任务. 工作队列(即任务队列)背后的主要思想是避免立 ...

随机推荐

  1. table左边固定-底部横向滚动条-demo

    图: 代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...

  2. 百度云bae安装discuz论坛教程

    作者:孤风一剑   发布:2013-05-11 13:37   栏目:站长在线   点击:6,846次   41条评论 各位草根们有福啦,弄了几天,终于可以在bae上搭建discuz论坛了,下面我就简 ...

  3. Law of large numbers and Central limit theorem

    大数定律 Law of large numbers (LLN) 虽然名字是 Law,但其实是严格证明过的 Theorem weak law of large number (Khinchin's la ...

  4. jqgrid 合并表头

    参考:http://www.trirand.com/jqgridwiki/doku.php?id=wiki:groupingheadar jQuery("#表格id").jqGri ...

  5. Pytorch dataset自定义【直播】2019 年县域农业大脑AI挑战赛---数据准备(二),Dataset定义

    在我的torchvision库里介绍的博文(https://www.cnblogs.com/yjphhw/p/9773333.html)里说了对pytorch的dataset的定义方式. 本文相当于实 ...

  6. dir815_FW_102.bin路由器固件解压碰到的坑

    在跟随大神kczwa1进行路由器漏洞分析时,对dir815_FW_102.bin 固件文件用binwalk -e dir815_FW_102.bin命令进行解压时,在根目录squashfs-root下 ...

  7. 「CF1C Ancient Berland Circus」

    CF第一场比赛的最后一题居然是计算几何. 这道题的考点也是比较多,所以来写一篇题解. 前置芝士 平面直角坐标系中两点距离公式:\(l=\sqrt{(X_1-X_2)^2+(Y_1-Y_2)^2}\) ...

  8. Content Provider基础

    1.Content Provider为存储和获取数据提供了统一的接口. 2.Content Provider可以在不同的应用程序之间共享数据. 3.Android为常见的一些数据提供了ContentP ...

  9. ch4 背景图像基础

    如果希望网站有一个好看的背景,只需将背景应用于主体元素,即在body上应用background-image,默认情况下浏览器水平和垂直的重复显示背景图像,让图像平铺在整个页面上,可以选择背景图像是垂直 ...

  10. vs2015中安装cplex攻略以及解决丢失cplex.dll问题

    转:http://blog.sina.com.cn/s/blog_61f0374801014swp.html 按:相信配置过CPLEX的人大多有过痛苦而难忘的经历,本人亦不例外,纠结挣扎了一个下午加一 ...