RabbitMQ入门实战
RabbitMQ 是一个开源的消息中间件,实现了高级消息队列协议(AMQP),用于在分布式系统中进行消息传递。它能够在应用之间传递消息,解耦应用组件,提高系统的可伸缩性和可维护性。RabbitMQ 使用高级消息队列协议(AMQP),这是一种开放的、标准化的协议,定义了消息格式、交换方式、队列管理等规范。拥有强大的社区支持,提供了广泛的文档和示例。它还支持插件机制,可以根据实际需求进行扩展。下面就对rabbitMQ进行实战。
官网:RabbitMQ: easy to use, flexible messaging and streaming — RabbitMQ
1. 基本概念
- 消息队列:消息队列是一种在不同应用之间传递数据的机制。在RabbitMQ中,消息队列是通过Exchange(交换机)来进行消息路由的。
- Exchange:Exchange负责将消息路由到一个或多个队列。RabbitMQ支持不同类型的Exchange,包括Direct、Fanout、Topic等。
- Queue:Queue是消息的容器,消息在发送到Exchange后通过Routing Key被路由到一个或多个Queue中。
2. 使用场景
消息中间件经常被用来处理异步、削峰填谷,和多个组件之间进行解耦的作用。
- 异步任务处理:RabbitMQ可以作为任务队列,将任务发布到队列中,然后由后台工作者异步处理。这在分布式系统中很常见,可以提高系统的响应速度。
- 事件驱动架构:RabbitMQ可以用于实现事件驱动的架构,不同组件之间通过消息进行通信。当某个事件发生时,可以将消息发送到队列中,由其他组件进行消费。
- 日志收集:RabbitMQ可以用于日志收集系统,应用程序将日志消息发送到队列中,日志收集器订阅队列并将日志保存到数据库或其他存储中。
3. RabbitMQ实战
3.1 rabbitMQ安装
这里演示使用docker-compose方式安装,创建一个docker-compose.yml文件并写入以下内容
version: '3'services:rabbitmq:image: "rabbitmq:management"container_name: "rabbitmq-container"ports:- "5672:5672" # RabbitMQ 默认端口- "15672:15672" # RabbitMQ 管理界面端口volumes:- "./rabbitmq-data:/var/lib/rabbitmq" # 数据文件挂载environment:RABBITMQ_DEFAULT_USER: "rabbit"RABBITMQ_DEFAULT_PASS: "rabbit1qz"
执行命令拉取并启动容器
docker-compose up -d
执行命令查看docker容器是否正常
docker ps | grep rabbit

然后地址栏http://localhost:15672/访问rabbitMQ管理界面
输入用户名密码可以看到如下界面,在这个页面上可以创建Exchanges和Queue,这里就不赘述了,大家想了解的可以参考官方文档。
3.1 代码集成
上面安装完MQ组件之后,就可以用java代码进行连接测试了。使用Maven添加RabbitMQ的Java客户端库到项目里:
<dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.14.0</version> <!-- 替换为最新版本 -->
</dependency>
3.2 发送消息
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Channel;public class MessageSender {private final static String QUEUE_NAME = "hello";public static void main(String[] argv) throws Exception {// 创建连接工厂ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost"); // RabbitMQ服务器地址// 创建连接try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {// 声明队列channel.queueDeclare(QUEUE_NAME, false, false, false, null);// 发送消息String message = "Hello, RabbitMQ!";channel.basicPublish("", QUEUE_NAME, null, message.getBytes());System.out.println(" [x] Sent '" + message + "'");}}
}
3.3 接收消息
import com.rabbitmq.client.*;public class MessageReceiver {private final static String QUEUE_NAME = "hello";public static void main(String[] argv) throws Exception {// 创建连接工厂ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost"); // RabbitMQ服务器地址// 创建连接try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {// 声明队列channel.queueDeclare(QUEUE_NAME, false, false, false, null);// 定义消息处理器DeliverCallback deliverCallback = (consumerTag, delivery) -> {String message = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received '" + message + "'");};// 监听队列,接收消息channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});// 持续监听队列,不会退出System.out.println(" [*] Waiting for messages. To exit press Ctrl+C");Thread.sleep(Long.MAX_VALUE);}}
}
以上示例中,MessageSender类用于发送消息到名为"hello"的队列,而MessageReceiver类用于监听该队列并接收消息。
4. RabbitMQ高级特性
RabbitMQ 提供了许多高级特性,包括持久化、消息确认、事务、死信队列等。下面将结合 Java 完整代码进行说明这些高级特性。
1. 持久化
持久化确保在 RabbitMQ 服务器重启时,队列和消息不会丢失。
代码示例
// 发布者代码
public class DurableProducer {// ...初始化 RabbitMQ 连接等代码...public void publishPersistentMessage(String message) {channel.basicPublish("", "durable_queue", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());System.out.println(" [x] Sent '" + message + "'");}
}// 订阅者代码
public class DurableSubscriber {// ...初始化 RabbitMQ 连接等代码...public void subscribeToPersistentMessages() {channel.queueDeclare("durable_queue", true, false, false, null);channel.basicConsume("durable_queue", true, (consumerTag, delivery) -> {String message = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received '" + message + "'");// 处理消息的逻辑...}, consumerTag -> {});}
}
2. 消息确认
消息确认确保消息已经被消费者成功处理。
代码示例
// 发布者代码
public class AckProducer {// ...初始化 RabbitMQ 连接等代码...public void publishAckMessage(String message) {channel.basicPublish("", "ack_queue", null, message.getBytes());System.out.println(" [x] Sent '" + message + "'");}
}// 订阅者代码
public class AckSubscriber {// ...初始化 RabbitMQ 连接等代码...public void subscribeToAckMessages() {channel.queueDeclare("ack_queue", false, false, false, null);channel.basicConsume("ack_queue", false, (consumerTag, delivery) -> {String message = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received '" + message + "'");// 处理消息的逻辑...// 手动发送消息确认channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);}, consumerTag -> {});}
}
3. 事务
RabbitMQ 支持事务,但由于性能问题,通常建议使用消息确认代替。
代码示例
// 发布者代码
public class TransactionalProducer {// ...初始化 RabbitMQ 连接等代码...public void publishTransactionalMessage(String message) throws IOException {try {channel.txSelect(); // 开启事务channel.basicPublish("", "transactional_queue", null, message.getBytes());System.out.println(" [x] Sent '" + message + "'");channel.txCommit(); // 提交事务} catch (IOException e) {channel.txRollback(); // 回滚事务e.printStackTrace();}}
}// 订阅者代码
public class TransactionalSubscriber {// ...初始化 RabbitMQ 连接等代码...public void subscribeToTransactionalMessages() {try {channel.queueDeclare("transactional_queue", false, false, false, null);while (true) {channel.txSelect(); // 开启事务GetResponse response = channel.basicGet("transactional_queue", true);if (response != null) {String message = new String(response.getBody(), "UTF-8");System.out.println(" [x] Received '" + message + "'");// 处理消息的逻辑...channel.txCommit(); // 提交事务} else {channel.txRollback(); // 回滚事务}}} catch (IOException e) {e.printStackTrace();}}
}
4. 死信队列
死信队列用于处理无法被消费者成功处理的消息。
代码示例
// 发布者代码
public class DeadLetterProducer {// ...初始化 RabbitMQ 连接等代码...public void publishDeadLetterMessage(String message) {Map<String, Object> headers = new HashMap<>();headers.put("x-dead-letter-exchange", "dead_letter_exchange");headers.put("x-dead-letter-routing-key", "dl_queue");AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().headers(headers).build();channel.basicPublish("", "original_queue", properties, message.getBytes());System.out.println(" [x] Sent '" + message + "'");}
}// 订阅者代码
public class DeadLetterSubscriber {// ...初始化 RabbitMQ 连接等代码...public void subscribeToDeadLetterMessages() {channel.exchangeDeclare("dead_letter_exchange", BuiltinExchangeType.DIRECT);channel.queueDeclare("dl_queue", false, false, false, null);channel.queueBind("dl_queue", "dead_letter_exchange", "");channel.queueDeclare("original_queue", false, false, false, null);channel.queueBind("original_queue", "", "original_queue");channel.basicConsume("original_queue", false, (consumerTag, delivery) -> {String message = new String(delivery.getBody(), "UTF-8");System.out.println(" [x] Received '" + message + "'");// 处理消息的逻辑...// 模拟处理失败,将消息发送到死信队列channel.basicNack(delivery.getEnvelope().getDeliveryTag(), false, false);}, consumerTag -> {});}
}
这些是 RabbitMQ 的一些高级特性的简单示例。在实际项目中,具体的实现可能会更加复杂,并需要根据场景进行适当的调整。
5. 总结
RabbitMQ作为一款强大的消息中间件,在异步任务处理、事件驱动架构以及日志收集等场景中都有广泛的应用。通过简单的代码实例,我们了解了RabbitMQ的基本概念以及如何在Java中使用RabbitMQ进行消息的发送和接收。
希望本文能够帮助大家入门RabbitMQ,并在实际项目中灵活应用消息队列的机制。
相关文章:
RabbitMQ入门实战
RabbitMQ 是一个开源的消息中间件,实现了高级消息队列协议(AMQP),用于在分布式系统中进行消息传递。它能够在应用之间传递消息,解耦应用组件,提高系统的可伸缩性和可维护性。RabbitMQ 使用高级消息队列协议…...
vue3-模版引用ref
1. 介绍 概念:通过 ref标识 获取真实的 dom对象或者组件实例对象 2. 基本使用 实现步骤: 调用ref函数生成一个ref对象 通过ref标识绑定ref对象到标签 代码如下: 父组件: <script setup> import { onMounted, ref } …...
C# 十大排序算法
以下是常见的十大排序算法(按照学习和实现的顺序排列): 冒泡排序(Bubble Sort)选择排序(Selection Sort)插入排序(Insertion Sort)希尔排序(Shell Sort&…...
面试之Glide如何绑定Activity的生命周期
Glide绑定Activity生命周期 Glide.with() 下面都是它的重载方法,Context,Activity,FragmentActivity, Fragment, android.app.Fragment fragment,View都可以作为他的参数,内容大同小异,都是先getRetriever࿰…...
从 fatal 错误到 sync.Map:Go中 Map 的并发策略
为什么 Go 语言在多个 goroutine 同时访问和修改同一个 map 时,会报出 fatal 错误而不是 panic?我们该如何应对 map 的数据竞争问题呢? 这篇文章将带你一步步了解背后的原理,并引出解决 map 并发问题的方案。 Map 数据竞争 首先…...
Simon算法详解
0.0 Intro 相关的算法: Deutsh-Jozsa算法: 第一个量子算法对经典算法取得指数级加速的算法 美中不足在于只能确定函数是平衡的还是非平衡的,无法确定函数具体的内容,即无法直接解出函数 Bernstein-Vazirani算法ÿ…...
jrebel IDEA 热部署
1 下载 2022.4.1 JRebel and XRebel - IntelliJ IDEs Plugin | Marketplace 2 选择下载好的zip 离线安装IDEA 插件 重启IDEA 3 打开 [Preference -> JRebel & XRebel] 菜单,输入 GUID address 为 https://jrebel.qekang.com/1e67ec1b-122f-4708-87d…...
pdf拆分成各个小pdf的方法
背景:由于某些缘故,一个大的pdf需要拆分成页数少的pdf,或者pdf需要去掉指定页,那么就有必要对pdf进行重新编辑,这里需要用到一个库,直接进行操作即可。 当使用Python时,可以使用PyMuPDF库来拆分PDF文件。以下是一个示例代码, import fitz # PyMuPDF def split_pdf(i…...
IntelliJ IDEA 常用快捷键一览表(通用型,提高编写速度,类结构、查找和查看源码,替换与关闭,调整格式)
文章目录 IntelliJ IDEA 常用快捷键一览表1-IDEA的日常快捷键第1组:通用型第2组:提高编写速度(上)第3组:提高编写速度(下)第4组:类结构、查找和查看源码第5组:查找、替换…...
MSVS C# Matlab的混合编程系列2 - 构建一个复杂(含多个M文件)的动态库:
前言: 本节我们尝试将一个有很多函数和文件的Matlab算法文件集成到C#的项目里面。 本文缩语: MT = Matlab 问题提出: 1 我们有一个比较复杂的Matlab文件: 这个MATLAB的算法,写了很多的算法函数在其他的M文件里面,这样,前面博客的方法就不够用了。会报错: 解决办法如下…...
上位机图像处理和嵌入式模块部署(qt图像处理)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 很多人一想到图像处理,本能的第一反应就是opencv,这也没有错。但是呢,这里面还是有一个问题的,不知…...
AI教我学编程之C#类的实例化与访问修饰符
前言 在这篇文章中,我将带大家深入了解C#编程语言的核心概念,包括类的实例化、访问修饰符的应用,以及C#中不同数据类型的默认值。我会通过逐步分析和具体实例,详细解释如何在C#中正确创建和操作对象,并探讨如何通过访…...
【笔记】Blender4.0建模入门-3物体的基本操作
Blender入门 ——邵发 3.1 物体的移动 演示: 1、选中一个物体 2、选中移动工具 3、移动 - 沿坐标轴移动 - 在坐标平面内移动 - 自由移动(不好控制) 选中物体:右上的大纲窗口,点击物体名称,物体的轮…...
一文详解 Berachain 测试网:全面介绍与教程,bitget wallet教程
什么是Berachain? Berachain(web3.bitget.com/zh-CN/assets/berachain-wallet)是一种尖端区块链技术,使用 Cosmos SDK 构建的 Layer-1,兼容以太坊虚拟机(EVM)。它基于一种独特的概念,…...
小程序使用echarts图表-雷达图
本文介绍下小程序中如何使用echarts 如果是通过npm安装,这样是全部安装的,体积有点大 我这边是使用echarts中的一个组件来实现的,下边是具体流程,实际效果是没有外边的红色边框的,加红色边框的效果是这篇说明 1.echa…...
MacM1Pro Parallels19.1.0 CentOS7.9 Install PostgrepSQL
相关阅读 MacM1Pro安装 Parallels Desktop 19.1.0 https://blog.csdn.net/qq_41594280/article/details/135420241 MacM1Pro Parallels安装Parallels Tools https://blog.csdn.net/qq_41594280/article/details/135398780 MacM1Pro Parallels安装CentOS7.9 https://blog.csdn.n…...
Golang 中如何实现 Set
在Go编程中,数据结构的选择对解决问题至关重要。本文将探讨如何在 GO 中实现 set 和 bitset 两种数据结构,以及它们在Go中的应用场景。 Go 的数据结构 Go 内置的数据结构并不多。工作中,我们最常用的两种数据结构分别是 slice 和 map&#…...
记录一下uniapp 集成腾讯im特别卡(已解决)
uniapp的项目运行在微信小程序 , 安卓 , ios手机三端 , 之前这个项目集成过im,不过版本太老了,0.x的版本, 现在需要添加客服功能,所以就升级了 由于是二开 , 也为了方便 , 沿用之前的webview嵌套腾讯IM的方案 , 选用uniapp集成ui ,升级之后所有安卓用户反馈点击进去特别卡,几…...
React16源码: React中的updateHostRoot的源码实现
HostRoot 的更新 1 )概述 HostRoot 是一个比较特殊的节点, 因为在一个react应用当中它只会有一个 HostRoot, 它对应的 Fiber 对象是我们的 RootFiber 对象重点在于它的更新过程 2 )源码 定位到 packages/react-reconciler/src/ReactFiberBeginWork.js…...
Template -- React
React 版本 Node 21.6.0Npm 10.2.4 项目 创建 npm init vite 项目名称reactjsnpm inpm run dev 依赖 npm i axios # 网络 npm i antd --save # UI npm i ant-design/icons npm i react-router-dom # 路由npm i sass -D # …...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...
