详解RabbitMQ工作模式之发布订阅模式
目录
发布订阅模式
概念
概念介绍
特点和优势
应用场景
注意事项
代码案例
引入依赖
常量类
编写生产者代码
编写消费者1代码
运行代码
发布订阅模式
概念
RabbitMQ的发布订阅模式(Publish/Subscribe)是一种消息传递模式,它允许消息生产者(Publisher)将消息发送到交换机(Exchange),然后交换机根据路由规则将消息广播到一个或多个队列,最后由消费者(Subscriber)从队列中接收并处理消息。
图中X表⽰交换机, 在订阅模型中,多了⼀个Exchange⻆⾊, 过程略有变化。
概念介绍
Exchange: 交换机 (X).
作⽤: ⽣产者将消息发送到Exchange, 由交换机将消息按⼀定规则路由到⼀个或多个队列中(上图中⽣产者将消息投递到队列中, 实际上这个在RabbitMQ中不会发⽣. )
RabbitMQ交换机有四种类型: fanout,direct, topic, headers, 不同类型有着不同的路由策略. AMQP协议⾥还有另外两种类型, System和⾃定义, 此处不再描述.
1. Fanout:⼴播,将消息交给所有绑定到交换机的队列(Publish/Subscribe模式)
2. Direct:定向,把消息交给符合指定routing key的队列(Routing模式)
3. Topic:通配符,把消息交给符合routing pattern(路由模式)的队列(Topics模式)
4. headers类型的交换器不依赖于路由键的匹配规则来路由消息, ⽽是根据发送的消息内容中的headers属性进⾏匹配. headers类型的交换器性能会很差,⽽且也不实⽤,基本上不会看到它的存在.
Exchange(交换机)只负责转发消息, 不具备存储消息的能⼒, 因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息就会丢失
RoutingKey: 路由键.⽣产者将消息发给交换器时, 指定的⼀个字符串, ⽤来告诉交换机应该如何处理这个消息.
Binding Key:绑定. RabbitMQ中通过Binding(绑定)将交换器与队列关联起来, 在绑定的时候⼀般会指定⼀个Binding Key, 这样RabbitMQ就知道如何正确地将消息路由到队列了.
⽐如下图: 如果在发送消息时, 设置了RoutingKey 为orange, 消息就会路由到Q1
当消息的Routing key与队列绑定的Bindingkey相匹配时,消息才会被路由到这个队列.
BindingKey其实也属于路由键中的⼀种, 官⽅解释为:the routingkey to use for the binding.
可以翻译为:在绑定的时候使⽤的路由键. ⼤多数时候,包括官⽅⽂档和RabbitMQJava API 中都把
BindingKey和RoutingKey看作RoutingKey, 为了避免混淆,可以这么理解:
1. 在使⽤绑定的时候,需要的路由键是BindingKey.
2. 在发送消息的时候,需要的路由键是RoutingKey
特点和优势
1.解耦合:生产者和消费者之间通过交换机进行解耦。生产者无需知道消息将被传递到哪些队列,消费者也无需知道消息来自哪个生产者。这种解耦合使得系统更加灵活和可扩展。
2.多播:支持多个消费者同时处理同一条消息,实现消息的多播效果。这有助于提高系统的并行处理能力和容错性。
3.灵活性:可以根据需要使用不同类型的交换机和绑定规则,以满足不同的消息传递需求。RabbitMQ提供了多种交换机类型,如直接交换机、扇形交换机、主题交换机等。
应用场景
发布订阅模式适用于需要将消息广播给多个消费者的场景,例如:
1.实时通知:如系统状态更新、订单状态变更等实时事件的通知。通过发布订阅模式,可以将这些事件广播给所有感兴趣的消费者。
2.日志记录:将应用程序的日志信息广播到多个日志处理服务进行处理和存储。这有助于实现日志的集中管理和分析。
3.事件处理:在事件驱动架构中,将事件作为消息发布到交换机,由多个消费者订阅并处理这些事件。这有助于实现事件的异步处理和分布式处理。
注意事项
1.消息持久化:为了确保消息在RabbitMQ服务器重启后不会丢失,可以将消息和队列标记为持久性。这样,即使服务器发生故障,消息仍然可以被消费者接收和处理。
2.消息确认:RabbitMQ支持消息确认机制,确保消息在成功处理后才会从队列中删除。这有助于防止消息丢失和重复处理。
3.负载均衡:在发布订阅模式中,多个消费者可以监听同一个队列或不同的队列。为了实现负载均衡,可以配置多个消费者来处理同一个队列中的消息。
代码案例
引入依赖
<!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client --> <dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.21.0</version> </dependency>
常量类
public class Constants {public static final String HOST = "47.98.109.138";public static final int PORT = 5672;public static final String USER_NAME = "study";public static final String PASSWORD = "study";public static final String VIRTUAL_HOST = "aaa";//发布订阅模式public static final String FANOUT_EXCHANGE = "fanout.exchange";public static final String FANOUT_QUEUE1 = "fanout.queue1";public static final String FANOUT_QUEUE2 = "fanout.queue2";
}
编写生产者代码
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import rabbitmq.constant.Constants;import java.io.IOException;
import java.util.concurrent.TimeoutException;public class Producer {public static void main(String[] args) throws IOException, TimeoutException {//1. 建立连接ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost(Constants.HOST);connectionFactory.setPort(Constants.PORT); //需要提前开放端口号connectionFactory.setUsername(Constants.USER_NAME);//账号connectionFactory.setPassword(Constants.PASSWORD); //密码connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机Connection connection = connectionFactory.newConnection();//2. 开启信道Channel channel = connection.createChannel();//3. 声明交换机channel.exchangeDeclare(Constants.FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT, true);//4. 声明队列channel.queueDeclare(Constants.FANOUT_QUEUE1,true,false,false,null);channel.queueDeclare(Constants.FANOUT_QUEUE2,true,false,false,null);//5. 交换机和队列绑定channel.queueBind(Constants.FANOUT_QUEUE1,Constants.FANOUT_EXCHANGE,"");channel.queueBind(Constants.FANOUT_QUEUE2,Constants.FANOUT_EXCHANGE,"");//6. 发布消息String msg = "hello fanout....";channel.basicPublish(Constants.FANOUT_EXCHANGE,"", null, msg.getBytes());System.out.println("消息发送成功");//7. 释放资源channel.close();connection.close();}
}
编写消费者1代码
import com.rabbitmq.client.*;
import rabbitmq.constant.Constants;import java.io.IOException;
import java.util.concurrent.TimeoutException;public class Consumer1 {public static void main(String[] args) throws IOException, TimeoutException {//1. 建立连接ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost(Constants.HOST);connectionFactory.setPort(Constants.PORT); //需要提前开放端口号connectionFactory.setUsername(Constants.USER_NAME);//账号connectionFactory.setPassword(Constants.PASSWORD); //密码connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机Connection connection = connectionFactory.newConnection();//2. 开启信道Channel channel = connection.createChannel();//3. 声明队列channel.queueDeclare(Constants.FANOUT_QUEUE1,true,false,false,null);//4. 消费消息DefaultConsumer consumer = new DefaultConsumer(channel){//从队列中收到消息, 就会执行的方法@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("接收到消息:"+ new String(body));}};channel.basicConsume(Constants.FANOUT_QUEUE1, true, consumer);}
}
编写消费者2代码
import com.rabbitmq.client.*;
import rabbitmq.constant.Constants;import java.io.IOException;
import java.util.concurrent.TimeoutException;public class Consumer2 {public static void main(String[] args) throws IOException, TimeoutException {//1. 建立连接ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost(Constants.HOST);connectionFactory.setPort(Constants.PORT); //需要提前开放端口号connectionFactory.setUsername(Constants.USER_NAME);//账号connectionFactory.setPassword(Constants.PASSWORD); //密码connectionFactory.setVirtualHost(Constants.VIRTUAL_HOST); //虚拟主机Connection connection = connectionFactory.newConnection();//2. 开启信道Channel channel = connection.createChannel();//3. 声明队列channel.queueDeclare(Constants.FANOUT_QUEUE2,true,false,false,null);//4. 消费消息DefaultConsumer consumer = new DefaultConsumer(channel){//从队列中收到消息, 就会执行的方法@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("接收到消息:"+ new String(body));}};channel.basicConsume(Constants.FANOUT_QUEUE2, true, consumer);}
}
运行代码
运行生产者代码之后,可以在管理界面看到两个队列中都有1条消息。
由此我们可以看到,交换机收到的生产者生产的一条消息被广播到了两个队列,消费者都能够分别从这两个队列中得到一条消息并消费。
相关文章:

详解RabbitMQ工作模式之发布订阅模式
目录 发布订阅模式 概念 概念介绍 特点和优势 应用场景 注意事项 代码案例 引入依赖 常量类 编写生产者代码 编写消费者1代码 运行代码 发布订阅模式 概念 RabbitMQ的发布订阅模式(Publish/Subscribe)是一种消息传递模式,它允许消…...
什么是子网委派?
Azure 子网委派的概念 子网委托使您能够为所选的 Azure PaaS 服务指定一个特定的子网,并将其注入到您的虚拟网络中。子网委托为客户提供了完全的控制权,可以管理 Azure 服务与其虚拟网络的集成。 当您将子网委托给 Azure 服务时,您允许该服务为该子网建立一些基本的网络配…...

微信学习之导航功能
先看这个功能的效果: 然后开始学习吧。 一、我们这里用的是vant的Grid控件,首先我们导入: { "usingComponents": {"van-search": "vant/weapp/search/index","my-swiper":"../../components…...

城市内涝监测预警系统守护城市安全
一、系统背景 城市内涝是指由于强降水或连续性降水超过城市排水能力,导致城市内产生积水灾害的现象。随着气候变化和城市化进程的加快,城市内涝现象愈发频繁和严重。传统的城市排水系统已难以满足当前的城市排水需求,特别是在暴雨等极端天气条…...

用 CodeBuddy 搭建「MiniGoal 小目标打卡器」:一次流畅的 UniApp 开发体验
我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 在日常生活中,我们总是希望能够坚持一些小习惯,比如每天锻炼十分钟、读一页书、早睡十分…...

Web技术与Nginx网站环境部署
目录 一.web基础 1.域名和DNS (1).域名的概念 (2).hosts文件 (3).DNS (4).域名注册 2.网页与HTML (1).网页简介 (2).HTML &a…...

AI移动监测:仓储环境安全的“全天候守护者”
AI移动监测在仓储方面的应用:技术赋能与场景突破 一、背景:仓储环境的“隐形威胁”与AI破局 仓储行业长期面临设备损坏、货物损失、卫生隐患等风险。传统监控依赖人工巡检或固定摄像头,难以实时捕捉动态风险。例如: 动物入侵&a…...
【数据库】数据库故障排查指南
数据库故障排查指南 数据库连接问题 检查数据库服务是否正常运行,确认网络连接是否畅通,验证数据库配置文件的正确性,确保防火墙或安全组规则允许数据库端口的访问。 性能问题 分析慢查询日志,优化SQL语句,检查索引…...
mariadb 升级 (通过yum)
* 注意下 服务名, 有的服务器上是mysql,有的叫mariadb,mysqld的 #停止 systemctl stop mysql #修改源 vi /etc/yum.repos.d/MariaDB.repo baseurl http://yum.mariadb.org/11.4/centos7-amd64 #卸载 yum remove mysql #安装 yum install MariaDB-server galera-4 MariaDB-…...

2025年5月华为H12-821新增题库带解析
IS-IS核心知识 四台路由器运行IS-IS且已经建立邻接关系,区域号和路由器的等级如图中标记,下列说法中正确的有? R2和R3都会产生ATT置位的Level-1的LSPR1没有R4产生的LSP,因此R1只通过缺省路由和R4通信R2和R3都会产生ATT置位的Leve1-2的LSPR2和…...

用 python 编写的一个图片自动分类小程序(三)
图片自动分类识别小程序记录 2025/5/18 0:38修改程序界面,增加一些功能 用 python 编写的一个图片自动识别分类小程序。 操作系统平台:Microsoft Windows 11 编程语言和 IDE:python 3.10 Visual studio code 一:图片自动分…...
用户行为日志分析的常用架构
## 1. 经典Lambda架构 Lambda架构是一种流行的大数据处理架构,特别适合用户行为日志分析场景。 ### 1.1 架构组成 Lambda架构包含三层: - **批处理层(Batch Layer)**: 存储全量数据并进行离线批处理 - **实时处理层(Speed Layer)**: 处理最新数据&…...

初识 java
目录 前言 一、jdk,JRE和JVM之间的关系 二、JVM的内存划分 前言 初步了解 jdk,JRE,JVM 之间的关系,JVM 的内存划分。 一、jdk,JRE和JVM之间的关系 jdk 是 java 开发工具集,包含JRE; JRE 是…...
3D 数据交换格式(.3DXML)简介
3DXML 是一种基于 XML 的 3D 数据交换格式,由达索系统(Dassault Systmes)开发,主要用于其 CATIA、SOLIDWORKS 和 3DEXPERIENCE 等产品中。 基本概述 全称:3D XML开发者:达索系统主要用途:3D…...

frida 配置
1.环境 1.1 下载 frida-server firda-server github下载地址 这边推荐使用最新版的上一个版本 根据虚拟机自行选择版本 我使用这个版本 frida-server-16.7.17-android-x86_64 1.2 启动 frida-server-16.7.17-android-x86_64 将文件解压至虚拟机目录 使用adb命令执行 chmo…...

16-看门狗和RTC
一、独立看门狗 1、独立看门狗概述 在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞(不按照正常程序进行运行,如程序重启,但是如果我们填加看门狗的技术࿰…...

【AI论文】用于评估和改进大型语言模型中指令跟踪的多维约束框架
摘要:接下来的指令评估了大型语言模型(LLMs)生成符合用户定义约束的输出的能力。 然而,现有的基准测试通常依赖于模板化的约束提示,缺乏现实使用的多样性,并限制了细粒度的性能评估。 为了填补这一空白&…...
AUTOSAR图解==>AUTOSAR_SRS_TimeService
AUTOSAR TimeService模块详解 AUTOSAR经典平台时间服务分析与图解 目录 1. 概述2. TimeService架构分析 2.1 模块位置与组件关系2.2 模块功能职责3. TimeService组件结构 3.1 预定义定时器类型3.2 时间函数功能3.3 与GPT驱动关系4. TimeService定时器实例 4.1 实例数据结构4.2 …...
设计模式的原理及深入解析
创建型模式 创建型模式主要关注对象的创建过程,旨在通过不同的方式创建对象,以满足不同的需求。 工厂方法模式 定义:定义一个创建对象的接口,让子类决定实例化哪一个类。 解释:工厂方法模式通过定义一个创建对象的…...

Chromium 浏览器核心生命周期剖析:从 BrowserProcess 全局管理到 Browser 窗口实例
在 Chromium 浏览器架构中,BrowserProcess 和 Browser 是两个核心类,分别管理 浏览器进程的全局状态 和 单个浏览器窗口的实例。它们的生命周期设计直接影响浏览器的稳定性和资源管理。以下是它们的详细生命周期分析: 1. BrowserProcess 的生…...

易境通海外仓系统:一件代发全场景数字化解决方案
随着全球经济一体化和消费升级,一件代发业务的跨境电商市场规模持续增长。然而,一件代发的跨境运营也面临挑战,传统海外仓管理模式更因效率低下、协同困难成为业务扩张的瓶颈。 一、一件代发跨境运营痛点 1、多平台协同:卖家往往…...
Flink 非确定有限自动机NFA
Flink 是一个用于状态化计算的分布式流处理框架,而非确定有限自动机(NFA, Non-deterministic Finite Automaton)是一种在计算机科学中广泛使用的抽象计算模型,常用于正则表达式匹配、模式识别等领域。 Apache Flink 提供了对 NFA…...
YoloV9改进策略:卷积篇|风车卷积|即插即用
论文信息 论文标题:《Pinwheel-shaped Convolution and Scale-based Dynamic Loss for Infrared Small Target Detection》 论文链接:https://arxiv.org/pdf/2412.16986 GitHub链接:https://github.com/JN-Yang/PConv-SDloss-Data 论文翻译 摘要 https://arxiv.org/pd…...

【Python训练营打卡】day30 @浙大疏锦行
DAY 30 模块和库的导入 知识点回顾: 1. 导入官方库的三种手段 2. 导入自定义库/模块的方式 3. 导入库/模块的核心逻辑:找到根目录(python解释器的目录和终端的目录不一致) 作业:自己新建几个不同路径文件尝试下如何…...
超越想象:利用MetaGPT打造高效的AI协作环境
前言 在人工智能迅速发展的今天,如何让多个大语言模型(LLM)高效协同工作成为关键挑战。MetaGPT 作为一种创新的多智能体框架,成功模拟了一个真实软件公司的运作流程,实现了从需求分析到代码实现的全流程自动化&#x…...

仿腾讯会议——添加音频
1、实现开启或关闭音频 2、 定义信号 3、实现开始暂停音频 4、实现信号槽连接 5、回收资源 6、初始化音频视频 7、 完成为每个人创建播放音频的对象 8、发送音频 使用的是对象ba,这样跨线程不会立刻回收,如果使用引用,跨线程会被直接回收掉&a…...

虚幻引擎5-Unreal Engine笔记之`GameMode`、`关卡(Level)` 和 `关卡蓝图(Level Blueprint)`的关系
虚幻引擎5-Unreal Engine笔记之GameMode、关卡(Level) 和 关卡蓝图(Level Blueprint)的关系 code review! 参考笔记: 1.虚幻引擎5-Unreal Engine笔记之GameMode、关卡(Level) 和 关卡蓝图&…...
vue3 vite 项目中自动导入图片
vue3 vite 项目中自动导入图片 安装插件配置插件使用方法 安装插件 yarn add vite-plugin-vue-images -D 或者 npm install vite-plugin-vue-images -D配置插件 在 vite.config.js 文件中配置插件 // 引入 import ViteImages from vite-plugin-vue-images;plugins: [vue(),/…...

MTK zephyr平台:系统休眠流程
一、概述: 当内核没有需要调度的东西时,就会进入空闲状态。 CONFIG_PM=y时允许内核调用PM subsys,将空闲系统置于支持的电源状态之一。 Application负责设置唤醒事件,该事件通常是由SoC外围模块触发的中断,例如: SysTick、RTC、计数器、GPIO 并非所有外设在所有电源模式…...

涨薪技术|0到1学会性能测试第71课-T-SQL调优
前面的推文我们掌握了索引调优技术,今天给大家分享T-SQL调优技术。后续文章都会系统分享干货,带大家从0到1学会性能测试。 对T-SQL语句进行调校是DBA调优数据库性能的主要任务,因为不同的查询语句,即使查询出来的结果一致,其消耗的时间和系统资源也有所不同,所以如何使查…...