上一篇博文中,我们使用direct exchange 代替了fanout exchange,这次我们来看下topic exchange。

一、Topic Exchange介绍

topic exchange和direct exchange类似,都是通过routing key和binding key进行匹配,不同的是topic exchange可以为routing key设置多重标准。

direct路由器类似于sql语句中的精确查询;topic 路由器有点类似于sql语句中的模糊查询。

还记得吗?我们在《RabbitMQ入门:发布/订阅(Publish/Subscribe)》中对exchange的分类进行过介绍:

Direct:完全根据key进行投递的,例如,绑定时设置了routing key为”abc”,那么客户端提交的消息,只有设置了key为”abc”的才会投递到队列。
Topic:对key进行模式匹配后进行投递,符号”#”匹配一个或多个词,符号”*”匹配正好一个词。例如”abc.#”匹配”abc.def.ghi”,”abc.*”只匹配”abc.def”。
Fanout:不需要key,它采取广播模式,一个消息进来时,投递到与该交换机绑定的所有队列。
Headers:我们可以不考虑它。

下面是官网给出的工作模型(P代表生产者,X代表exhange,红色的Q代表队列,C代表消费者):

我们来分析下这个模型。

它发送的消息是用来描述动物的。路由键有三个单词:<speed>.<color>.<species>,第一个单词描述了速度,第二个描述了颜色,第三个描述了物种。
有三个绑定键,Q1绑定键为*.orange.*(关注所有颜色为orange的动物); Q2的绑定键有两个,分别是*.*.rabbit(关注所有的兔子)和lazy.#(关注所有速度为lazy的动物)。

因此,路由键为quick.orange.rabbit的消息将发送到Q1和Q2,路由键为quick.orange.fox的消息将发送到Q1,路由键为lazy.brown.fox的消息将发送到Q2。路由键为lazy.pink.rabbit的消息将发送到Q2,但是注意,它只会到达Q2一次,尽管它匹配了两个绑定键。路由键为quick.brown.fox的消息因为不和任意的绑定键匹配,所以将会被丢弃。

如果有人手一抖发了个lazy.orange.male.rabbit这种四个单词的,这个怎么办呢? 由于它和lazy.#匹配,因此将发送到Q2。

二、代码示例

接下来我们看下代码

  1. 生产者

    public class LogTopicSender {
    // exchange名字
    public static String EXCHANGE_NAME = "topicExchange"; public static void main(String[] args) {
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost("localhost");
    Connection connection = null;
    Channel channel = null;
    try {
    // 1.创建连接和通道
    connection = factory.newConnection();
    channel = connection.createChannel(); // 2.为通道声明topic类型的exchange
    channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC); // 3.发送消息到指定的exchange,队列指定为空,由exchange根据情况判断需要发送到哪些队列
    String routingKey = "info";
    // String routingKey = "log4j.error";
    // String routingKey = "logback.error";
    // String routingKey = "log4j.warn";
    String msg = " hello rabbitmq, I am " + routingKey;
    channel.basicPublish(EXCHANGE_NAME, routingKey, null, msg.getBytes());
    System.out.println("product send a msg: " + msg);
    } catch (IOException e) {
    e.printStackTrace();
    } catch (TimeoutException e) {
    e.printStackTrace();
    } finally {
    // 4.关闭连接 if (connection != null) {
    try {
    connection.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    } }
    }
  2. 消费者
    public class LogTopicReciver {
    
        public static void main(String[] args) {
    ConnectionFactory factory = new ConnectionFactory();
    factory.setHost("localhost");
    Connection connection = null;
    Channel channel = null;
    try {
    // 1.创建连接和通道
    connection = factory.newConnection();
    channel = connection.createChannel(); // 2.为通道声明topic类型的exchange
    channel.exchangeDeclare(LogTopicSender.EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
    // 3.创建随机名字的队列
    String queueName = channel.queueDeclare().getQueue(); // 4.建立exchange和队列的绑定关系
    String[] bindingKeys = { "#" };
    // String[] bindingKeys = { "log4j.*", "#.error" };
    // String[] bindingKeys = { "*.error" };
    // String[] bindingKeys = { "log4j.warn" };
    for (int i = 0; i < bindingKeys.length; i++) {
    channel.queueBind(queueName, LogTopicSender.EXCHANGE_NAME, bindingKeys[i]);
    System.out.println(" **** LogTopicReciver keep alive ,waiting for " + bindingKeys[i]);
    } // 5.通过回调生成消费者并进行监听
    Consumer consumer = new DefaultConsumer(channel) {
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope,
    com.rabbitmq.client.AMQP.BasicProperties properties, byte[] body) throws IOException { // 获取消息内容然后处理
    String msg = new String(body, "UTF-8");
    System.out.println("*********** LogTopicReciver" + " get message :[" + msg + "]");
    }
    };
    // 6.消费消息
    channel.basicConsume(queueName, true, consumer); } catch (IOException e) {
    e.printStackTrace();
    } catch (TimeoutException e) {
    e.printStackTrace();
    }
    }
    }
  3. 启动消费者,作为消费者1
  4. 分别将String[] bindingKeys = { "#" };改为String[] bindingKeys = { "log4j.*", "#.error" };/String[] bindingKeys = { "*.error" };/String[] bindingKeys = { "log4j.warn" };,然后启动作为消费者2、消费者3、消费者4
  5. 启动4次生产者,routing key分别为String routingKey = "info";、String routingKey = "log4j.error";、String routingKey = "logback.error";、String routingKey = "log4j.warn";
  6. 观察控制台log
    生产者:
    product send a msg: hello rabbitmq, I am info
    product send a msg: hello rabbitmq, I am log4j.error
    product send a msg: hello rabbitmq, I am logback.error
    product send a msg: hello rabbitmq, I am log4j.warn 消费者1:
    **** LogTopicReciver keep alive ,waiting for #
    *********** LogTopicReciver get message :[ hello rabbitmq, I am info]
    *********** LogTopicReciver get message :[ hello rabbitmq, I am log4j.error]
    *********** LogTopicReciver get message :[ hello rabbitmq, I am logback.error]
    *********** LogTopicReciver get message :[ hello rabbitmq, I am log4j.warn] 消费者2:
    **** LogTopicReciver keep alive ,waiting for log4j.*
    **** LogTopicReciver keep alive ,waiting for #.error
    *********** LogTopicReciver get message :[ hello rabbitmq, I am log4j.error]
    *********** LogTopicReciver get message :[ hello rabbitmq, I am logback.error]
    *********** LogTopicReciver get message :[ hello rabbitmq, I am log4j.warn] 消费者3:
    **** LogTopicReciver keep alive ,waiting for *.error
    *********** LogTopicReciver get message :[ hello rabbitmq, I am log4j.error]
    *********** LogTopicReciver get message :[ hello rabbitmq, I am logback.error] 消费者4:
    **** LogTopicReciver keep alive ,waiting for log4j.warn
    *********** LogTopicReciver get message :[ hello rabbitmq, I am log4j.warn]
  7. 观察RabbitMQ管理页面

RabbitMQ入门:主题路由器(Topic Exchange)的更多相关文章

  1. RabbitMQ之主题(Topic)【译】

    在上一节中,我们改进了我们的日志系统,替换使用fanout exchange仅仅能广播消息,使得选择性的接收日志成为可能. 虽然使用direct exchange改进了我们的系统,但是它仍然由他的局限 ...

  2. RabbitMQ入门学习系列(六) Exchange的Topic类型

    快速阅读 介绍exchange的topic类型,和Direct类型相似,但是增加了"."和"#"的匹配.比Direct类型灵活 Topic消息类型 特点是:to ...

  3. RabbitMQ入门_07_Fanout 与 Topic

    A. 用广播的方式实现发布订阅 参考资料:https://www.rabbitmq.com/tutorials/tutorial-three-java.html Fanout 类型的 Exchange ...

  4. RabbitMQ入门学习系列(五) Exchange的Direct类型

    快速阅读 利用Exchange的Direct类型,实现对队列的过滤,消费者启动以后,输入相应的key值,攻取该key值对应的在队列中的消息 . 从一节知道Exchange有四种类型 Direct,To ...

  5. RabbitMQ入门:总结

    随着上一篇博文的发布,RabbitMQ的基础内容我也学习完了,RabbitMQ入门系列的博客跟着收官了,以后有机会的话再写一些在实战中的应用分享,多谢大家一直以来的支持和认可. RabbitMQ入门系 ...

  6. RabbitMQ入门(5)——主题(Topic)

    前面我们介绍了通过使用direct exchage,改善了fanout exchange只能进行虚拟广播的方式.尽管如此,直接交换也有自身的局限,它不能基于多个条件路由. 在我们的日志系统中,也许我们 ...

  7. RabbitMQ入门详解以及使用

    目的: RabbitMQ简介 RabbitMQ安装及使用 Centos安装 Docker安装(今天选择Docker安装方法) RabbitMQ快速入门 交换机 RabbitMQ简介 各大主流中间件对比 ...

  8. netcore之RabbitMQ入门

    简介 RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息中间件,基于Erlang语言编写. AMQP是什么 AMQP 0-9-1(高级消息队列协议)是一种消息传递协议,它允许一致的客户端应 ...

  9. RabbitMQ指南之五:主题交换器(Topic Exchange)

    在上一章中,我们完善了我们的日志系统,用direct交换器替换了fanout交换器,使得我们可以有选择性地接收消息.尽管如此,仍然还有限制:不能基于多个标准进行路由.在我们的日志系统中,我们可能不仅希 ...

随机推荐

  1. tomcat 开启远程debug

    修改 tomcat  目录下  /bin/catelina.sh #                   execution immediately after startup. Default is ...

  2. 1925: [Sdoi2010]地精部落

    1925: [Sdoi2010]地精部落 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1929 Solved: 1227 [Submit][Statu ...

  3. javascript:typeof与instanceof区别

    from:http://www.wxwdesign.cn/article/skills/javascript_typeof_instanceof.htm JavaScript中typeof和insta ...

  4. 打开一个网站中的不同页面时,相同的js文件会被重复加载吗?

    作者:JasonYang链接:https://www.zhihu.com/question/41184156/answer/135195798来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非 ...

  5. 玩转Spring Boot 集成Dubbo

    玩转Spring Boot 集成Dubbo 使用Spring Boot 与Dubbo集成,这里我之前尝试了使用注解的方式,简单的使用注解注册服务其实是没有问题的,但是当你涉及到使用注解的时候在服务里面 ...

  6. 【PHP函数】json_decode() ---- 对 JSON 格式的字符串进行解码

    json_decode() --- 对 JSON 格式的字符串进行解码 1.用法: mixed json_decode ( string $json [, bool $assoc = false [, ...

  7. java 输出流 outputstream

    一:输入和输出概念 输入流(inputstream):对于java程序来说,从程序写入文件叫做输出. 输出流(outputstream):对于java程序来说,从文件读取数据,到java程序叫做输入. ...

  8. Mysql利用binlog日志恢复数据操作(转)

    a.开启binlog日志:1)编辑打开mysql配置文件/etc/mys.cnf[root@vm-002 ~]# vim /etc/my.cnf在[mysqld] 区块添加 log-bin=mysql ...

  9. dataTable配置项说明

    Datatables是一款jquery表格插件.它是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能. 官网地址:https://datatables.net/ 中文说明地址:http:/ ...

  10. 【PHP开发规范】继承与扩展:PSR-2 编码风格规范

    之前的一篇文章是对PSR-1的基本介绍 接下来是PSR-2 编码风格规范,它是 PSR-1 基本代码规范的继承与扩展. PSR-1 和PSR-2是PHP开发中基本的编码规范,大家其实都可以参考学习下, ...