2024.2.4 模拟实现 RabbitMQ —— 实现核心类

news2024/11/26 4:26:51

目录

引言

创建 Spring Boot 项目

编写 Exchange 实体类

编写 Queue 实体类

编写 Binding 实体类

编写 Message 实体类


引言

  • 上图为模块设计图

  • 此处实现核心类为了简便,我们引用 Lombok(可点击下方链接了解 Lombok 的使用)

IDEA 配置 Lombok

创建 Spring Boot 项目

1、创建一个 Spring Boot 项目 并 创建相应的目录结构


注意:

  • 消息队列中存在下列比较核心的概念
  1. 交换机(exchange)
  2. 队列(queue)
  3. 绑定(binding)
  4. 消息(message)
  • 上述这些均存在于 Broker Server 中,所以我们在 mqserver 目录中进行创建实体类

编写 Exchange 实体类

1、使用一个枚举类 枚举出三种交换机类型

public enum ExchangeType {
    DIRECT(0),
    FANOUT(1),
    TOPIC(2);

    private final int type;

    private ExchangeType(int type) {
        this.type = type;
    }

    private int getType() {
        return type;
    }
}

2、编写 Exchange 实体类

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;

import java.util.HashMap;
import java.util.Map;

/*
* 这个类表示一个交换机
* */
@Data
public class Exchange {
//    此处使用 name 来作为交换机的身份标识 (唯一的)
    private String name;
//    交换机类型,DIRECT,FANOUT,TOPIC
    private ExchangeType type = ExchangeType.DIRECT;
//    该交换机是否要持久化存储 ture 表示需要持久化;false 表示不必持久化
    private boolean durable = false;
//    针对 交换机 队列,绑定,消息.... 内存中也需要存储(执行效率高),硬盘上也需要存储(持久化)
//    有些交换机,队列,绑定等,是需要持久化存储,但是有些则不需要
//    用户使用的时候,就可以通过 开关(boolean 值)来决定是否真的需要持久化

//    如果当前交换机没人使用了,就会自动被删除(对于生产者而言)
//    这个属性暂时先列在这里,后续的代码中并没有真的实现这个自动删除功能(RabbitMQ 是有的)
    private boolean autoDelete = false;
//    argument 表示的是创建交换机时指定的一些额外的参数选项,后续代码中并没有真的实现对应的功能,先列出来(RabbitMQ 也是有的)
//    为了把这个 argument 给存到数据库中,就需要把 Map 转成 json 格式的字符串
    private Map<String,Object> arguments = new HashMap<>();
//    argument 可以称为 "参数" 或 "选项", 可以有,也可以没有,通过选项来开启不同的功能
}

编写 Queue 实体类

1、编写 Queue 实体类

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;

import java.util.HashMap;
import java.util.Map;

/*
* 这个类表示一个存储消息的队列
* MSG ——> Message
* */
@Data
public class MSGQueue {
//    表示队列的身份标识
    private String name;
//    标识队列是否持久化,true 持久化保存,false 表示不持久化
    private boolean durable = false;
//    这个属性为 true,表示这个队列只能被一个消费者使用(别人用不了)如果为 false 则是大家都能使用
//    这个 独占 功能,也是先把字段列在这里,具体的独占功能暂时先不实现
    private boolean exclusive = false;
//    为 ture 表示没有人使用之后,就自动删除  false 则是不会自动删除(对于消费者而言)
    private boolean autoDelete = false;
//    表示拓展参数,当前也是先列在这里,先暂时不实现
    private Map<String,Object> arguments = new HashMap<>();
}

注意:

  • 此处为了与标准库中的 Queue 类稍作区分,我们直接取名为 MSGQueue 类 

编写 Binding 实体类

1、编写 Binding 实体类

import lombok.Data;

/*
* 表示队列和交换机之间的关联关系
* */
@Data
public class Binding {
    private String exchangeName;
    private String queueName;
//    这里的 bindingKey 就是在出题
    private String bindingKey;

//    binding 这个东西,依附于 Exchange 和 Queue 的
//    比如,对于持久化来说,如果 Exchange 和 Queue 任何一个都没有持久化
//    此时你针对 Binding 持久化是没有任何意义的
}

编写 Message 实体类

  • Message 主要包含三个部分
  1. 属性部分 BasicProperties
  2. 正文部分 byte[]
  3. 辅助属性 offsetBeg、offsetEnd 、isValid

1、编写 Message 实体类

import lombok.Data;

import java.io.Serializable;
import java.util.UUID;

/*
* 表示一个要传递的消息
* 注意!!此处的 Message 对象,是需要能够在网络上删除,并且也需要能写入到文件中
* 此时就需要针对 Message 进行序列化和反序列化
* 此处使用 标准库自带的 序列化/反序列化 操作
* */
@Data
public class Message implements Serializable {
//    这两个属性是 Message 最核心的部分
    private BasicProperties basicProperties = new BasicProperties();
    private byte[] body;

//    下面的属性则是辅助用的属性
//    Message 后续会持久化到文件中(如果持久化的话)
//    一个文件中会存储很多的消息,如何找到某个消息,在文件中的具体位置呢?
//    使用下面两个偏移量来进行表示 [offsetBeg,offsetEnd)
//    这俩属性并不需要被序列化保存到文件中 此时消息一旦被写入文件之后,所在的位置就固定了,并不需要单独存储
//    这俩属性存在的目的,主要就是为了让内存中的 Message 对象,能够快速找到对应的硬盘上的 Message 的位置
    private transient long offsetBeg = 0; // 消息数据的开头距离文件开头的位置偏移(字节)
    private transient long offsetEnd = 0; // 消息数据的结尾距离文件开头的位置便宜(字节)

//    使用这个属性表示该消息在文件中是否是有效消息(针对文件中的消息,如果删除,使用逻辑删除的方式)
//    0x1 表示有效,0x0 表示无效
    private byte isValid = 0x1;

//    创建一个工厂方法,让工厂方法来帮我们封装一下创建 Message 对象的过程
//    这个方法中创建 Message 对象,会自动生成唯一的 MessageId
//    万一 routingKey 和 basicProperties 里的 routingKey 冲突,以外面的为主
    public static Message createMessageWithId(String routingKey, BasicProperties basicProperties,byte[] body) {
        Message message = new Message();
        if (basicProperties != null) {
            message.setBasicProperties(basicProperties);
        }
//        此处生成的 MessageId 以 M- 作为前缀
        message.setMessageId("M-" + UUID.randomUUID());
        message.setRoutingKey(routingKey);
        message.body = body;
//        此处是把 body 和 basicProperties 先设置出来,这俩个是 Message 的核心内容
//        而 offsetBeg,offsetEnd,isValid,则是消息持久化的时候才会用到,在把消息写入文件之前再进行设定
//        此处只是在内存中创建一个 Message 对象
        return message;
    }

    public String getMessageId() {
        return basicProperties.getMessageId();
    }

    private void setMessageId(String messageId) {
        basicProperties.setMessageId(messageId);
    }

    public String getRoutingKey() {
        return basicProperties.getRoutingKey();
    }

    public void setRoutingKey(String routingKey) {
        basicProperties.setRoutingKey(routingKey);
    }

    public int getDeliverMode() {
        return basicProperties.getDeliverMode();
    }

    public void setDeliverMode(int deliverMode) {
        basicProperties.setDeliverMode(deliverMode);
    }
}

注意点一:

  •  此处我们将使用标准库自带的方式进行序列化/反序列化,而不使用 JSON 方式
  • JSON 本质上是文本格式,即里面放的也是文本类型的数据
  • 而 Message 中存储的是 二进制数据
  • 所以我们直接让需要被序列化的类实现一个 Serializable 接口即可

注意点二:

  • 以往实现一个接口,都是为了重写里面的某个/某些方法
  • 但是 Serializable 接口无需重写任何方法

注意点三:

  • 如图所示,辅助属性 offsetBeg 和 offsetEnd 仅用于标识某一消息在文件中的具体位置
  • 而不是将这俩属性,像如同 属性部分 和 正文部分 序列化保存到文件中!
  • 所以我们给这两个成员变量加上 trasient 关键字,用于防止被序列化

注意点四:

  • UUID 是编程中,一种用来生成唯一 id 的算法

注意点五:

  • 数据库也好,硬盘文件也好,在删除数据时,很多时候均会使用到 逻辑删除
  • 不是真删除了,而是标记成 "无效"

2、编写属性部分 BasicProperties 

import lombok.Data;

import java.io.Serializable;

@Data
public class BasicProperties implements Serializable {
//    消息的唯一身份标识 此处为了保证 id 的唯一性,使用 UUID 来作为 messageId
    private String messageId;
//    是一个消息上带有的内容,和 bindingKey 做匹配
//    如果当前的交换机类型是 DIRECT,此时 routingKey 就表示要转发的队列名
//    如果当前的交换机类型是 FANOUT,此时 routingKey 无意义(不使用)
//    如果当前的交换机类型是 TOPIC,此时 routingKey 就要和 bindingKey 做匹配,符合要求才能转发给对应队列
    private String routingKey;

//    表示消息是否要持久化, 1 表示不持久化, 2 表示持久化 (RabbitMQ 就是这样做的)
    private  int deliverMode = 1;

//    其实针对 RabbitMQ 来说,BasicProperties 里面还有很多别的属性,其他的属性暂时先不考虑了
}

注意:

  • Message 实体类实现了 Serializable 接口用于序列化
  • BasicProperties 类作为 Message 的属性部分,也需实现 Serializable 接口用于序列化

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

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

相关文章

滑动列表(scroll view)

使用scroll view实现单行滑动列表。 只需要横向滑动&#xff0c;取消Scroll Rect的Vertical&#xff0c;并取消掉Scrollbar。 为Content添加两个组件 Grid Layout Group设置子节点布局 Content Size Fitter自适应Content大小 Padding:子节点与边界的距离。 Cell Size:子节点…

NLP_语言模型的雏形N-Gram

文章目录 N-Gram 模型1.将给定的文本分割成连续的N个词的组合(N-Gram)2.统计每个N-Gram在文本中出现的次数&#xff0c;也就是词频3.为了得到一个词在给定上下文中出现的概率&#xff0c;我们可以利用条件概率公式计算。具体来讲&#xff0c;就是计算给定前N-1个词时&#xff0…

DFS——连通性和搜索顺序

dfs的搜索是基于栈&#xff0c;但一般可以用用递归实现&#xff0c;实际上用的是系统栈。有内部搜索和外部搜索两种&#xff0c;内部搜索是在图的内部&#xff0c;内部搜索一般基于连通性&#xff0c;从一个点转移到另一个点&#xff0c;或者判断是否连通之类的问题&#xff0c…

Github开源项目Excalidraw:简洁易用的手绘风格白板工具

Excalidraw是Github上的一个开源项目&#xff0c;它提供了一个简洁易用的手绘图形创建工具&#xff0c;用户可以通过它创建流程图、示意图、架构图和其他各种图形。本文将介绍Excalidraw的特点和功能&#xff0c;并探讨其在技术层面上的优势和扩展能力。 GitHub地址&#xff1a…

android inset 管理

目录 简介 Insets管理架构 Insets相关类图 app侧的类 WMS侧的类 inset show的流程 接口 流程 WMS侧确定InsetsSourceControl的流程 两个问题 窗口显示时不改变现有的inset状态 全屏窗口上的dialog 不显示statusbar问题 View 和 DecorView 设置insets信息 输入法显…

通讯基本概念

通信的方式有多种&#xff0c;按数据传输方式可分为串行通讯和并行通信&#xff1b;按通信数据同步方式可分为同步通信和异步通信&#xff1b;按数据通信的方向可分为 一、串行通信和并行通信 串行通信&#xff1a;设备之间通过少量的数据信号线&#xff08;一般是8根以下&am…

Windows自动化实现:系统通知和任务栏图标自定义

文章目录 Windows自动化的三个小工具系统通知任务栏图标使用pystray实现使用infi.systray实现 Windows自动化的三个小工具 系统通知 import win10toastwin10toast.ToastNotifier().show_toast("eee", "休息一下", icon_path"icon.ico", durati…

scikit-learn 1.3.X 版本 bug - F1 分数计算错误

如果您正在使用 scikit-learn 1.3.X 版本&#xff0c;在使用 f1_score() 或 classification_report() 函数时&#xff0c;如果参数设置为 zero_division1.0 或 zero_divisionnp.nan&#xff0c;那么函数的输出结果可能会出错。错误的范围可能高达 100%&#xff0c;具体取决于数…

第十三篇【传奇开心果系列】Python的OpenCV库技术点案例示例:光流估计

传奇开心果短博文系列 系列短博文目录Python的OpenCV库技术点案例示例:光流估计短博文目录前言一、光流估计介绍二、Lucas-Kanade光流介绍和示例代码三、Horn-Schunck光流介绍和示例代码四、cv::calcOpticalFlowPyrLK()函数实现光流估计介绍和示例代码五、光流估计用于运动分析…

shell——2月3日总结

操作系统有什么用&#xff1f; 操作系统是计算机系统中的核心软件&#xff0c;负责管理和协调计算机的硬件和软件资源&#xff0c;提供用户界面&#xff0c;并执行用户程序。 硬件管理&#xff1a;操作系统管理计算机的硬件资源&#xff0c;包括处理器、内存、磁盘、外部设备等…

MySQL原理(一)架构组成之逻辑模块(2)缓存机制

前面提到了mysql的逻辑模块中包含Query Cache 。 一、查询缓存 1、作用 MySQL查询缓存即缓存查询数据的SQL文本及查询结果,用Key-Value的形式保存在服务器内存中。当查询命中缓存,MySQL会立刻返回结果,跳过了解析,优化和执行阶段。 2、查询缓存的命中条件 &#xff08;1&a…

基于ChatGLM.cpp实现低成本对ChatGLM3-6B的量化加速

文章目录 1. 参考2. ChatGLM3 介绍3. 本地运行3.1 硬件配置3.2 下载ChatGLM3代码3.3 量化模型3.4 编译和运行3.4.1 编译3.4.12 运行 4. python绑定4.1 安装4.2 使用预先转换的 GGML 模型 总结 前面两章分别有讲到基于MacBook Pro M1芯片运行chatglm2-6b大模型和如何在本地部署c…

《Python 网络爬虫简易速速上手小册》第1章:Python 网络爬虫基础(2024 最新版)

文章目录 1.1 网络爬虫简介1.1.1 重点基础知识讲解1.1.2 重点案例&#xff1a;社交媒体数据分析1.1.3 拓展案例1&#xff1a;电商网站价格监控1.1.4 拓展案例2&#xff1a;新闻聚合服务 1.2 网络爬虫的工作原理1.2.1 重点基础知识讲解1.2.2 重点案例&#xff1a;股票市场数据采…

玩家笔记:幻兽帕鲁搭建服务器开服教程

玩转幻兽帕鲁服务器&#xff0c;阿里云推出新手0基础一键部署幻兽帕鲁服务器教程&#xff0c;傻瓜式一键部署&#xff0c;3分钟即可成功创建一台Palworld专属服务器&#xff0c;成本仅需26元&#xff0c;阿里云服务器网aliyunfuwuqi.com分享2024年新版基于阿里云搭建幻兽帕鲁服…

MyBatis之环境搭建以及实现增删改查

MyBatis之环境搭建以及实现增删改查 前言准备工作1.保证数据库已启动2. 创建Person表 MyBatis开发环境搭建1.下载MyBatis jar包2.下载MySQL的JDBC驱动3.新建Java工程&#xff08;Java8&#xff09;&#xff0c;导入MyBatis的jar包以及JDBC驱动 实现步骤1. 创建Peron类2. 编写Ma…

Log360,引入全新安全与风险管理功能,助力企业积极抵御网络威胁

ManageEngine在其SIEM解决方案中推出了安全与风险管理新功能&#xff0c;企业现在能够更主动地减轻内部攻击和防范入侵。 SIEM 这项新功能为Log360引入了安全与风险管理仪表板&#xff0c;Log360是ManageEngine的统一安全信息与事件管理&#xff08;SIEM&#xff09;解决方案…

【复现】WordPress html5-video-player SQL 注入漏洞_39

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 在WordPress中播放各种视频文件。一个简单&#xff0c;可访问&#xff0c;易于使用和完全可定制的视频播放器&#xff0c;适用于所…

0基础学习VR全景平台篇第141篇:如何制作卫星航拍全景

大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 很多人都看过或者拍摄过航拍全景&#xff0c;其效果相比于普通的地拍的确有着更加震撼的拍摄效果&#xff0c;但是受限于无人机高度&#xff0c;以及禁飞区等等限制&#xff0c;导致很多大场景无法展示完全&a…

绝地求生:盘点游戏内七款真人脸模,你最喜欢哪款?

从27.1版本更新后&#xff0c;游戏内上线了荣都地图代言人吴彦祖和李政宰的真人脸模&#xff0c;从此闲游盒的各位盒友灵魂搭配的资源库里又多了两位英俊脸庞&#xff0c;那么今天闲游盒来盘点一下游戏内上线的七款真人脸模&#xff0c;看看大家更喜欢哪款呢? 吴彦祖和李政宰 …

前端文艺复兴:Vue3真的需要Pinia吗?

前言 说起Pinia&#xff0c;熟悉 vue3 开发的程序员肯定不会陌生&#xff0c;甚至被vue官方推荐取代vuex&#xff0c;成为vue全家桶之一。 疑惑 还记得之前用 vuex 时&#xff0c;更改 state 还分同步和异步&#xff08;这里有尤雨溪的回答www.zhihu.com/question/48… &…