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

目录

引言

创建 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.mfbz.cn/a/371765.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【npm】修改npm全局安装包的位置路径

问题 全局安装的默认安装路径为&#xff1a;C:\Users\admin\AppData\Roaming\npm&#xff0c;缓存路径为&#xff1a;C:\Users\admin\AppData\Roaming\npm_cache&#xff08;其中admin为自己的用户名&#xff09;。 由于默认的安装路径在C盘&#xff0c;太浪费C盘内存啦&#…

C语言之数据在内存中的存储

目录 1. 整数在内存中的存储2. 大小端字节序和字节序判断什么是大小端&#xff1f;为什么有大小端&#xff1f;练习1练习2练习3练习4练习5练习6 3. 浮点数在内存中的存储浮点数存的过程浮点数取得过程练习题解析 1. 整数在内存中的存储 在讲解操作符的时候&#xff0c;我们已经…

算法学习——华为机考题库7(HJ41 - HJ45)

算法学习——华为机考题库7&#xff08;HJ41 - HJ45&#xff09; HJ41 称砝码 描述 现有n种砝码&#xff0c;重量互不相等&#xff0c;分别为 m1,m2,m3…mn &#xff1b; 每种砝码对应的数量为 x1,x2,x3…xn 。现在要用这些砝码去称物体的重量(放在同一侧)&#xff0c;问能称…

前端 - 基础 列表标签 - 自定义列表 详解

使用场景 &#xff1a; 常用于对术语或名词进行解释和描述&#xff0c;定义列表的列表前没有任何项目符号。 在 HTML 标签中&#xff0c; < dl > 标签用于定义 描述列表 &#xff08; 或定义列表 &#xff09; 该标签会与 <dt> ( 定义项目/名字 ) 和 <dd…

从0搭建react+ts+redux+axios+antd项目

文章目录 一、安装及初始化二、TypeScript配置三、Webpack配置四、Prettier统一编码风格五、使用less六、Antd 安装及使用七、添加redux及使用八、添加Router及配置九、安装axios十、echarts按需引入 本文介绍了如何用creat-react-app脚手架搭建一个react项目的基本结构&#x…

UE4 C++ 静态加载类和资源

静态加载类和资源&#xff1a;指在编译时加载&#xff0c;并且只能在构造函数中编写代码 .h //增加所需组件的头文件 #include "Components/SceneComponent.h" //场景组件 #include "Components/StaticMeshComponent.h" //静态网格体组件 #include &qu…

VS2019+CAXACAD2023二次开发教程(一、环境搭建)

前言 CAXACAD2023的二次开发相关文件和库都在installpath\CRX\的文件夹下。 CAXACAD2023的默认开发环境是VS2019,如果是用VS2019的环境话,可以直接安装"installpath\CRX\Wizard\CRXWizard_VS2019.exe"这个插件,安装好后就可以一键新建的项目,新建的项目会自动帮…

【漏洞复现】EPON上行A8-C政企网关信息泄露漏洞

Nx01 产品简介 EPON上行A8-C政企网关是一款终端产品&#xff0c;提供企业网络解决方案。 Nx02 漏洞描述 EPON上行A8-C政企网关敏感信息泄露漏洞&#xff0c;攻击者通过敏感信息泄露获取管理员密码。 Nx03 产品主页 fofa-query: "ZXECS" && title"Web…

蓝桥杯每日一题----区间dp

前言 暂时没啥好说的&#xff0c;直接进入正题吧 引入 涂色PAINT 读题发现要求的是使一段区间满足要求的最小操作次数&#xff0c;考虑用动态规划去做。 第一步&#xff1a;考虑缩小规模&#xff0c;这里的规模其实就是区间长度&#xff0c;那么dp数组应该可以表示某个区间&…

certificate has expired错误解决

npm ERR! request to https://registry.npm.taobao.org/nodemon failed, reason: certificate has expired错误解决 npm在安装依赖包时出现以下错误。 作为最后的手段&#xff0c;你可以配置npm忽略SSL证书验证。这不是一个推荐的解决方案&#xff0c;因为它会降低安全性&…

window 镜像---负载篇

前提&#xff1a;需要修改window的powershell执行脚本的策略 步骤&#xff1a;以管理员身份打开powershell&#xff0c;执行 Get-ExecutionPolicy查看当前执行策略&#xff0c;若返回值是Restricted&#xff0c;需执行Set-ExecutionPolicy RemoteSigned powershell 版本信息&am…

计算机网络第6章(应用层)

6.1、应用层概述 我们在浏览器的地址中输入某个网站的域名后&#xff0c;就可以访问该网站的内容&#xff0c;这个就是万维网WWW应用&#xff0c;其相关的应用层协议为超文本传送协议HTTP 用户在浏览器地址栏中输入的是“见名知意”的域名&#xff0c;而TCP/IP的网际层使用IP地…

YouTrack 用户登录提示 JIRA 错误

就算输入正确的用户名和密码&#xff0c;我们也得到了下面的错误信息&#xff1a; youtrack Cannot retrieve JIRA user profile details. 解决办法 出现这个问题是因为 YouTrack 在当前的系统重有 JIRA 的导入关联。 需要把这个导入关联取消掉。 找到后台配置的导入关联&a…

【JMeter】使用技巧

在这此对新版本jmeter的学习温习的过程&#xff0c;发现了一些以前不知道的功能&#xff0c;所以&#xff0c;整理出来与大分享。本文内容如下。 如何使用英文界面的jmeter如何使用镜像服务器Jmeter分布式测试启动Debug 日志记录搜索功能线程之间传递变量 如何使用英文界面的…

SpringBoot实现统一异常处理

文章目录 前言实现步骤定义统一响应对象类定义业务异常枚举接口和实现定义业务异常基类定义全局异常处理切面测试和验证 总结 前言 近日心血来潮想做一个开源项目&#xff0c;目标是做一款可以适配多端、功能完备的模板工程&#xff0c;包含后台管理系统和前台系统&#xff0c…

Docker 搭建mysql 集群(二)

PXC方案 很明显 PXC方案在任何一个节点写入的数据都会同步到其他节点&#xff0c;数据双向同步的&#xff08;在任何节点上都可以同时读写&#xff09; 创建MySQL PXC集群 1 安装PXC镜像 docker pull percona/percona-xtradb-cluster:5.7.21 2 为PXC镜像改名 docker tag pe…

数据分析基础之《pandas(3)—DataFrame运算》

一、算术运算 1、add() 加法运算 2、sub() 减法运算 3、想要得到每天的涨跌幅大小&#xff0c;求出每天close-open价格差 # 算术运算 close data[close] open1 data[open] # 收盘价减去开盘价 data[m_price_change] close.sub(open1) data.head() 二、逻辑运算 1、逻辑…

Transformer实战-系列教程5:Vision Transformer 源码解读3

&#x1f6a9;&#x1f6a9;&#x1f6a9;Transformer实战-系列教程总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 6、Block类------构造函数 class Block(nn.Module):def __init__(self, config, vis):super(Blo…

【C++】类和对象(2)

这篇博客继续学习类和对象~&#xff0c;主要介绍了类的6个默认成员函数。 目录 类的6个默认成员函数 构造函数 概念 特性 析构函数 概念 特性 拷贝构造函数 特性 赋值运算符重载 运算符重载 赋值运算符重载 前置和后置重载 日期类的实现 const成员 取地址及cons…

FTP口令问题

FTP&#xff08;File Transfer Protocol &#xff0c;文件传输协议&#xff09;是一个文件传输协议&#xff0c;用户通 过FTP可从客户机程序向远程主机上传或下载文件&#xff0c;常用于网站代码维护、 日常 源码备份等。如果攻击者通过FTP匿名访问或者通过弱口令破解获取FTP…