RabbitMQ交换机(Exchanges)

news2024/11/15 11:07:55

目录

一、概念

二、临时队列

三、绑定

四、Fanout(扇出交换机)

(一)介绍

(二)实战 

五、Direct(直接交换机)

(一)介绍

(二)实战

六、Topic(主题交换机)

(一)介绍

(二)案例

(三)实战

七、Header(头部交换机)


一、概念

        RabbitMQ 消息传递模型的核心思想是 : 生产者生产的消息从不会直接发送到队列 。实际上,通常生产者甚至都不知道这些消息传递传递到了哪些队列中。
        相反,生产者只能将消息发送到交换机 (exchange) ,交换机工作的内容非常简单,一方面它接收来自生产者的消息,另一方面将它们推入队列。交换机必须确切知道如何处理收到的消息。是应该把这些消息放到特定队列还是说把他们到许多队列中还是说应该丢弃它们。这就的由交换机的类型来决定。

交换机的类型直接(direct), 主题(topic) ,标题(headers) , 扇出(fanout)

无名 exchange

第一个参数是交换机的名称。空字符串表示默认或无名称交换机:消息能路由发送到队列中其实
是由 routingKey(bindingkey) 绑定 key 指定的,如果它存在的话
channel.basicPublish("", QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes() );

二、临时队列

        每当我们连接到 Rabbit 时,我们都需要一个全新的空队列,为此我们可以创建一个具有 随机名称 的队列 ,或者能让服务器为我们选择一个随机队列名称那就更好了。其次 一旦我们断开了消费者的连 接,队列将被自动删除。
创建临时队列的方式如下 :
String queueName = channel.queueDeclare().getQueue();

 

三、绑定

什么是 bingding 呢, binding 其实是 exchange queue 之间的桥梁,它告诉我们 exchange 和那个队列进行了绑定关系。比如说下面这张图告诉我们的就是 X Q1 Q2 进行了绑定

 

四、Fanout(扇出交换机)

(一)介绍

Fanout 这种类型非常简单。正如从名称中猜到的那样,它是将接收到的所有消息 广播 到它知道的
所有队列中。系统中默认有些 exchange 类型

 

(二)实战 

 我们声明一个logs交换机以及创建两个临时队列绑定在交换机上,routeKey为空字符串,当EmitLog生产者向logs交换机发消息时两个队列都接收得到。这个即为扇出交换机。

 ReceiveLogs01 将接收到的消息打印在控制台

public class ReceiveLogs01 {

    private final static String EXCHANGE_NAME = "logs";

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMqUtils.getChannel();
        /*
         * 生成一个临时的队列,队列名字随机
         */
        String queueName = channel.queueDeclare().getQueue();
        // 将临时队列绑定在我们定义的交换机上,路由Key为空字符串
        channel.queueBind(queueName, EXCHANGE_NAME, "");
        // 接收消息回调函数
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("ReceiveLogs01控制台打印接收到的消息:" + new String(message.getBody()));
        };
        
        channel.basicConsume(queueName, true, deliverCallback, (consumerTag -> {}));
    }
}

 ReceiveLogs02 将接收到的消息打印在控制台 

public class ReceiveLogs02 {

    private final static String EXCHANGE_NAME = "logs";

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMqUtils.getChannel();
        /*
         * 生成一个临时的队列,队列名字随机
         */
        String queueName = channel.queueDeclare().getQueue();
        // 将临时队列绑定在我们定义的交换机上,路由Key为空字符串
        channel.queueBind(queueName, EXCHANGE_NAME, "");

        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("ReceiveLogs02控制台打印接收到的消息:" + new String(message.getBody()));
        };

        channel.basicConsume(queueName, true, deliverCallback, (consumerTag -> {}));
    }
}

 EmitLog 发送消息给两个消费者接收

public class EmitLog {

    private final static String EXCHANGE_NAME = "logs";

    public static void main(String[] args) throws IOException {
        // 获取信道
        Channel channel = RabbitMqUtils.getChannel();
        // 交换机声明,在生产者声明消费者方就不用声明了
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        // 控制台输入内容充当消息发送
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()) {
            String message = scanner.next();
            channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
            System.out.println("生产者发出消息");
        }
    }
}

总结

当交换机内的队列routeKey为空字符串时,此时向该交换机发送消息且routeKey也为空字符串的话那么所有的队列都接收得到消息,即为扇出交换机。

五、Direct(直接交换机)

(一)介绍

当我们想对某一个队列单独发送消息,可以根据设置不同的routeKey来达到这种效果,这就是直接交换机。

在上面这张图中,我们可以看到 X 绑定了两个队列,绑定类型是 direct 。队列 Q1 绑定键为 orange , 队列 Q2 绑定键有两个 : 一个绑定键为 black ,另一个绑定键为 green.
在这种绑定情况下,生产者发布消息到 exchange 上,绑定键为 orange 的消息会被发布到队列
Q1 。绑定键为 black和green 的消息会被发布到队列 Q2 ,其他消息类型的消息将被丢弃。

多重绑定无非就是绑定的时候多出一条queueBind

channel.queueBind(queue_name, EXCHANGE_NAME, "info");
channel.queueBind(queue_name, EXCHANGE_NAME, "waring");

(二)实战

 

此时队列的声明需要放在消费者方,因为每个消费者代表不同的队列,对于交换机的声明可以放在生产者

消费者01

public class ReceiveLogsDirect01 {

    private static final String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMqUtils.getChannel();
        String queue_name = "console";
        channel.queueDeclare(queue_name, false, false, false, null);
        channel.queueBind(queue_name, EXCHANGE_NAME, "info");
        channel.queueBind(queue_name, EXCHANGE_NAME, "waring");
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("ReceiveLogsDirect01收到消息" + new String(message.getBody()));
        };
        channel.basicConsume(queue_name, deliverCallback, (consumerTag -> {}));
    }
}

消费者02

public class ReceiveLogsDirect02 {

    private static final String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMqUtils.getChannel();

        String queue_name = "disk";
        channel.queueDeclare(queue_name, false, false, false, null);
        channel.queueBind(queue_name, EXCHANGE_NAME, "error");
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("ReceiveLogsDirect02收到消息" + new String(message.getBody()));
        };
        channel.basicConsume(queue_name, deliverCallback, (consumerTag -> {}));
    }
}

生产者

public class EmitLogDirect {

    private final static String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMqUtils.getChannel();
        /*
         * 生产者并不知道消息会发向哪个队列,他只是指明找哪个交换机中的路由key
         * 由交换机去寻找队列传递消息
         */

        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()) {
            String message = sc.next();
            channel.basicPublish(EXCHANGE_NAME, "info", null,  message.getBytes());
        }
    }
}

总结

我们可以通过指定routeKey来向对应的队列单独发消息,即为直接交换机

六、Topic(主题交换机)

(一)介绍

        发送到类型是 topic 交换机的消息的 routing_key 不能随意写,必须满足一定的要求,它 必须是一个单 词列表,以点号分隔开 。这些单词可以是任意单词,比如说: "stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit".这种类型的。当然这个单词列表最多不能超过 255 个字节。

 

在这个规则列表中,其中有两个替换符是大家需要注意的
  • *(星号)可以代替一个单词
  • #(井号)可以替代零个或多个单词

(二)案例

 队列Q1的routeKey为“*.orange.*”,Q2的routeKey有两个,分别为“*.*.rabbit”和“lazy.#”

 

上图是一个队列绑定关系图,我们来看看他们之间数据接收情况是怎么样的
quick.orange.rabbit           被队列 Q1Q2 接收到
lazy.orange.elephant        被队列 Q1Q2 接收到
quick.orange.fox         被队列 Q1 接收到
lazy.brown.fox             被队列 Q2 接收到
lazy.pink.rabbit            虽然满足两个绑定但只被队列 Q2 接收一次
quick.brown.fox           不匹配任何绑定不会被任何队列接收到会被丢弃
quick.orange.male.rabbit         是四个单词不匹配任何绑定会被丢弃
lazy.orange.male.rabbit           是四个单词但匹配 Q2
当队列绑定关系是下列这种情况时需要引起注意
  • 当一个队列绑定键是#,那么这个队列将接收所有数据,就有点像 fanout
  • 如果队列绑定键当中没有#*出现,那么该队列绑定类型就是 direct

(三)实战

 消费者01

public class ReceiveLogsTopic01 {

    public static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMqUtils.getChannel();
        String queueName = "Q1";
        channel.queueDeclare(queueName, false, false, false, null);
        channel.queueBind(queueName, EXCHANGE_NAME,  "*.orange.*");

        System.out.println("ReceiveLogsTopic01等待接收消息...");
        DeliverCallback deliverCallback = (consumeTag, message) -> {
            System.out.println("接收队列:" + queueName + "绑定键:" + message.getEnvelope().getRoutingKey());
            System.out.println("接收到消息:" + new String(message.getBody()));
        };

        channel.basicConsume(queueName, true, deliverCallback, (consumerTag -> {}));

    }
}

消费者02

public class ReceiveLogsTopic02 {

    public static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMqUtils.getChannel();
        String queueName = "Q2";
        channel.queueDeclare(queueName, false, false, false, null);
        channel.queueBind(queueName, EXCHANGE_NAME, "*.*.rabbit");
        channel.queueBind(queueName, EXCHANGE_NAME, "lazy.#");
        System.out.println("ReceiveLogsTopic02等待接收消息...");
        DeliverCallback deliverCallback = (consumeTag, message) -> {
            System.out.println("接收队列:" + queueName + "绑定键:" + message.getEnvelope().getRoutingKey());
            System.out.println("接收到消息:" + new String(message.getBody()));
        };

        channel.basicConsume(queueName, true, deliverCallback, (consumerTag -> {}));
    }
}

生产者

public class EmitLogTopic {

    public static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitMqUtils.getChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");

        Map<String, String> bindingKeyMap = new HashMap<>();
        bindingKeyMap.put("quick.orange.rabbit","被队列 Q1Q2 接收到");
        bindingKeyMap.put("lazy.orange.elephant","被队列 Q1Q2 接收到");
        bindingKeyMap.put("quick.orange.fox","被队列 Q1 接收到");
        bindingKeyMap.put("lazy.brown.fox","被队列 Q2 接收到");
        bindingKeyMap.put("lazy.pink.rabbit","虽然满足两个绑定但只被队列 Q2 接收一次");
        bindingKeyMap.put("quick.brown.fox","不匹配任何绑定不会被任何队列接收到会被丢弃");
        bindingKeyMap.put("quick.orange.male.rabbit","是四个单词不匹配任何绑定会被丢弃");
        bindingKeyMap.put("lazy.orange.male.rabbit","是四个单词但匹配 Q2");

        for(Map.Entry<String, String> bindingKeyMapEntry : bindingKeyMap.entrySet()) {
            String bindingKey = bindingKeyMapEntry.getKey();
            String message = bindingKeyMapEntry.getValue();
            channel.basicPublish(EXCHANGE_NAME, bindingKey, null, message.getBytes());
            System.out.println("生产者发出消息:" + message);
        }
    }
}

结果

 

七、Header(头部交换机)

由于header交换机不常用,这里简单介绍

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/372466.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode】1255. 得分最高的单词集合

1255. 得分最高的单词集合 题目描述 你将会得到一份单词表 words&#xff0c;一个字母表 letters &#xff08;可能会有重复字母&#xff09;&#xff0c;以及每个字母对应的得分情况表 score。 请你帮忙计算玩家在单词拼写游戏中所能获得的「最高得分」&#xff1a;能够由 …

我看谁还敢说不懂git

文章目录一、Git介绍1.1、Git的作用1.2、Git的理念1.3、Git的特点1.4、Git对比SVN二、Git的概念2.1、Git基础概念三、Git的基本操作3.1、使用Git管理一个代码仓库的流程3.2、Git常用命令介绍四、Git状态的变化五、Git安装和配置5.1、Git的安装5.2、Git的配置六、Git的高级操作6…

【阅读笔记】SecureML: A System for ScalablePrivacy-Preserving Machine Learning

1. Motivation 针对机器学习中的出现的数据隐私泄露的风险&#xff0c;提出了线性回归、逻辑回归以及简单神经网络的隐私保护模型。 2. Contributions 2.1 为线性回归、逻辑回归以及神经网络设计安全计算协议 2.1.1.1 线性回归 线性回归损失函数为&#xff1a; , 采用SG…

数据分析:某电商优惠卷数据分析

数据分析&#xff1a;某电商优惠卷数据分析 作者&#xff1a;AOAIYI 专栏&#xff1a;python数据分析 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;AOAIYI首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可…

单变量回归问题

单变量回归问题 对于某房价问题&#xff0c;x为房屋大小&#xff0c;h即为预估房价&#xff0c;模型公式为&#xff1a; hθ(x)θ0θ1xh_{\theta}(x)\theta_{0}\theta_{1}x hθ​(x)θ0​θ1​x 要利用训练集拟合该公式&#xff08;主要是计算θ0、θ1\theta_{0}、\theta_{1}θ…

JavaScript DOM和BOM

目录 查找html元素 1.通过id 2.通过标签名 3.通过类名 DOM 1.创建动态的HTML内容 2.修改元素内容 3.改变HTML属性 4.改变css样式 DOM事件 DOM节点 1.添加HTML元素 2.删除HTML元素 浏览器对象 1.Window对象 2.Screen对象 3.History对象 4.Location对象 5.Navi…

深入理解java虚拟机精华总结:jvm内存模型(运行时数据区域)、对象、OOM异常

深入理解java虚拟机精华总结&#xff1a;jvm内存模型、对象、OOM异常jvm内存模型对象对象的创建对象的内存布局对象的访问定位OOM异常Java堆溢出栈溢出方法区溢出直接内存溢出以前读过好几遍《深入理解java虚拟机》这本书&#xff0c;最近又打算重读一遍&#xff0c;并且做一些…

一个接口多个实现如何选择注入对应的Bean_@Primary_@Resource_@Qualifier_@ConditionalOnProperty

文章目录引入结论案例Primary 指定默认注入的BeanQualifier配合Autowired 按名称注入对应的BeanResource 默认按照类型注入&#xff0c;可指定名称注入ConditionalOnProperty 结合配置文件统一设置bean的注入引入 在springboot中&#xff0c;如果一个接口有多个实现&#xff0…

SpringMVC - 13 - SpringMVC执行流程

文章目录1、SpringMVC常用组件2、DispatcherServlet初始化过程a>初始化WebApplicationContextb>创建WebApplicationContextc>DispatcherServlet初始化策略3、DispatcherServlet调用组件处理请求a>processRequest()b>doService()c>doDispatch()d>processDi…

【Neo4j】图数据库CypherQueryLanguage随笔

CQL语言随笔 一、Cyther关系描述 如图&#xff1a;唐僧&#xff0c;孙悟空&#xff0c;白骨精三者的关系图&#xff1a; Cypher语言描述他们的关系&#xff1a; (孙悟空)<-[:赶走]-(唐僧)-[:被骗]->(白骨精)-[:被打死]->(孙悟空) 二、CQL语言的使用案例 创建结点…

七、HTTPTomcatServlet

1&#xff0c;Web概述 1.1 Web和JavaWeb的概念 Web是全球广域网&#xff0c;也称为万维网(www)&#xff0c;能够通过浏览器访问的网站。 在我们日常的生活中&#xff0c;经常会使用浏览器去访问百度、京东、传智官网等这些网站&#xff0c;这些网站统称为Web网站。如下就是通…

_react

React 中 keys 的作用是什么&#xff1f; Keys是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识 在开发过程中&#xff0c;我们需要保证某个元素的 key 在其同级元素中具有唯一性。在 React Diff 算法中React 会借助元素的 Key 值来判断该元素是新近创建的还…

ADAS-可见光相机之Cmos Image Sensor

引言 “ 可见光相机在日常生活、工业生产、智能制造等应用有着重要的作用。在ADAS中更是扮演着重要的角色&#xff0c;如tesla model系列全车身10多个相机&#xff0c;不断感知周围世界。本文着重讲解下可见光相机中的CIS(CMOS Image Sensor)。” 定义 光是一种电磁波&…

如何在 iPhone 上恢复已删除的通话记录/通话记录

您的通话记录/通话记录可能很重要&#xff0c;尤其是当您想要拨打之前联系过但未保存的号码时。如果您碰巧删除了通话记录&#xff08;有意或无意&#xff09;&#xff0c;本指南将帮助您了解如何检索它们并找回您需要使用的所有记录。我们将根据您的情况和您拥有的工具讨论不同…

【Tomcat 】Tomcat 架构原理解析到架构设计借鉴

Tomcat 发展这么多年&#xff0c;已经比较成熟稳定。在如今『追新求快』的时代&#xff0c;Tomcat 作为 Java Web 开发必备的工具似乎变成了『熟悉的陌生人』&#xff0c;难道说如今就没有必要深入学习它了么&#xff1f;学习它我们又有什么收获呢&#xff1f; 静下心来&#…

一文让你彻底理解关于消息队列的使用

一、消息队列概述 消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用解耦&#xff0c;异步消息&#xff0c;流量削锋等问题&#xff0c;实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ&#xff0c;Rabbit…

Spring Security认证研究

1.项目中认证的三种方式&#xff1a; 1.统一认证 认证通过由认证服务向给用户颁发令牌&#xff0c;相当于访问系统的通行证&#xff0c;用户拿着令牌去访问系统的资源。 2.单点登录&#xff0c;对于微服务项目&#xff0c;因为包含多个模块&#xff0c;所以单点登录就是使得用户…

烙铁使用方法

烙铁使用 烙铁是硬件工程师最经常使用的工具之一,一把性能保持良好的烙铁能帮助我们快速进行电路调试。烙铁第一次加热时采用焊锡均匀涂覆在烙铁头上,以便去除包在烙铁头上面的氧化物。在工作中我们需要根据情况选择合适的烙铁头类型,合适的温度进行操作。完成焊接后要在烙铁…

TypeError: load() missing 1 required positional argument: ‘Loader‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理…

BLIP2-图像文本预训练

文章目录摘要解决问题算法模型结构通过frozen图像编码器学习视觉语言表征图像文本对比学习&#xff08;ITC&#xff09;基于图像文本生成&#xff08;ITG&#xff09;图文匹配&#xff08;ITM&#xff09;从大规模语言模型学习视觉到语言生成模型预训练预训练数据预训练图像编码…