• 第02篇:手写JavaRPC框架之设计思路


    作者: 西魏陶渊明
    博客: https://blog.springlearn.cn/

    天下代码一大抄, 抄来抄去有提高, 看你会抄不会抄!

    一、前言

    隔壁老李又在喷我了: “完犊子了,小编这绝对是为了骗粉丝,而水的一篇文章,到了第二篇竟然还没有开始写代码,又是一篇纯概念文章”。

    我也想写代码,但是在没有讲清楚思路之前,一定不要上来就蛮干,不然就毫无设计可言了。小编向各位观众老爷保证,下一篇文章绝对上代码。

    本篇文章非常重要,这是我们本系列文章中的重中之重,本篇文章的主要内容就是设计我们自己的通信协议及架构,可以这样说如果没有了本篇文章的内容,就不可能实现RPC。因为RPC的最基本要求就是能实现远程通信。本篇文章是讲述通信层的设计思路,下一篇就是实战的编写。(ps: 其实下一篇比较好写,因为代码我早就写完了嘻嘻,而这一篇竟然酝酿了一周还写的…不忍直视)

    二、目标

    本篇文章主要会围绕以下三方面展开叙述,希望在通读全篇后,大家都能在脑子中形成对这三个方面的认识,因为下面的三个方面是通信层搭建的主要指导思想。

    在这里插入图片描述

    1. 设计我们自己的通信协议
    2. 确定我们的通信层的架构
    3. 确定我们的工程结构

    2.1 为什么我们要设计自己的通信协议呢?

    上一篇我们也说了,实现RPC可以基于http也可以基于tcp。他们各有各的好处,如果是基于http其实我们的挑战就相对比较小一些,因为实现http的协议已经是在太多了,我们只用通过代理进行层层封装即可,而我们之所以要自己实现通信协议就是。

    在这里插入图片描述
    作为Java程序猿还是要对底层通信协议的具体实现有点了解的。如果不了解的话也没关系,你只要知道他是二进制数据就可以了。我们一步一步通过代码编写将二进制数据转换成我们Java语言能够认识的数据就好了。如果这个过程你学会了,那么一通百通,http如何实现的其实大概也能知道猜到一点。

    2.2 为什么要讲通信层的架构?

    怎么理解架构?

    作为一个有经验的开发者,都会清楚,我们写代码就如同写文章。好的代码一定是思路清晰的,思路清晰的代码耦合性一定是很少的。我们举一个例子,最近大环境不好,大厂裁员较多,很多小伙伴都要面试吧,就举一个面试的问题,通过这个例子来解释下什么是架构。

    • 面试官说: 同学做一下自我介绍吧。

    首先我们不能懵啊,如果懵了就说明没有头绪了,这样就容易讲乱,没有头绪在开发过程中的体现就是代码写的杂乱。比如你在介绍家乡的时候突然穿插了一下爱好,而在讲爱好的时候,又穿插的讲了一下家乡。这样就会导致主题不分明,听者会感觉会乱。所以这里我们就需要 单一职责。首先定义清楚你的讲话的结构,然后每个结构点就一个职责。

    如下我们设计的面试架构是这些点:

    姓名,家乡,大学,专业,兴趣爱好,单位职称 .

    下面我们只用实现每个点的内容(主题清晰),最终将他组装成完成的自我介绍回答;

    // 姓名,家乡,大学,专业,兴趣爱好,单位职称 
    public interface Introduce{
         // 这是一个介绍类,负责介绍自己
         public void introduce();
    }
    public class XiaoMing implements Introduce{
    
         // 将任务进行拆分,拆分的维度是逻辑顺序,然后抽离出方法,抽离的维度是单一职责。
         // 这样的好处是工能化,模块化,便于复用。
         public void introduce(){
             sout("我叫小明");
             // 主题介绍家乡
             introduceHometown();
             // 主题介绍学校
             introduceSchool();
             // 主题介绍专业
             introduceMajor();
             // 主题介绍兴趣爱好
             introduceInterest();
             sout("从业xx年,目前在公司的职称是xxx");
         }
         
        private void introduceHometown(){
             sout("我的老家是河南南阳")
             sout("我的家乡就坐落在河南南阳邓州市")
             sout("邓州市一个美丽的城市,是中国邓姓的发源地")
             sout("邓州也是河南境内人口最多的一个县级城市")
         }
         
         private void introduceSchool(){
             sout("我大学是在河南大学")
             sout("河南大学简称河大,是一所位于中国河南省开封市涵盖文、史、哲、经、管、
             法、理、工、医、农、教育、艺术等12个学科门类的省部共建型综合性公立大学。")
         }
         
         private void introduceMajor(){
             sout("我的专业是计算机与信息工程")
         }
         
         private void introduceInterest(){
             sout("我的个人爱好是写博客、打游戏、做美食、偶会也会跑跑步")
         }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    有没有发现单一职责的设计,会很大程度提高我们的代码利用率呢? 我们要的就是这个效果,所以我们再开始编码之前,最好提前定义清楚我们的架构是怎么样的。

    上面的例子,不知道小编有没有给大家解释清楚,但是总归我们的目的,是要在设计的时候就要明确责任划分,尽可能的单一职责。尽可能的解耦。

    要想设计一个好的框架,首先一定要有一个好的架构设计。这一点我们可以直接参考dubbo的设计架构。

    在这里插入图片描述
    上半部分不用看,我们只用看通信层就好了。

    • serialize 序列化层,负责将二进制数据转成Java认识的数据类型
    • transport 传输层,负责发送和接受数据
    • exchange 转换层,通信层和业务逻辑层转换的地方。
    • protocol 协议层,告诉serialize用什么协议来encode和decode数据的

    所以说,天下代码一大抄,抄来抄去有提高,就看你会抄不会抄了
    我们的设计就主要参考dubbo来了。

    2.3 工程结构设计

    在这里插入图片描述

    目前市面上的框架基本上都是自己来定制通信层,而通信层基本也不会单独的提供出去。但是本系列小编希望是通信层和业务能分开。通信层可以做RPC也可以利用通信层去实现消息队列或者是web容器。所以因为这个设计,就要求我们的项目能单独的去发布。所以我们整体的项目结构是由三个部分组成的,如下。

    在这里插入图片描述

    三、核心知识点

    3.1 通信层协议定义

    什么是协议呢?

    其实就是规则,我们按照什么样的方式将二进制数据转换成Java对象。

    如下图,我们的一条数据会分为4个部分

    1. 第一部分占用一个字节是协议标记,用来标记是http协议还是自定义协议。
    2. 第二部分占用一个字节是序列化标记,用来确定我们的真实报文使用什么来进行序列化和反序列化。
    3. 第三部分占用四个字节,用来表示数据的字节长度,确定真实报文的长度。
    4. 第四部分长度不固定,是真实的传输数据。最终会通过第二部分将这些二进制数据转换成Java对象。

    在这里插入图片描述
    以上就是我们定义的数据解析协议,通过上面的规则将二进制数据,转换成Java对象。

    读到这里你有没有一点收获呢?

    有没有发现,其实协议的概念,其实很简单,就是一个规则或者说是约定。能让彼此都互相认识的一个约定。

    在本系列中,我们会自定义一个协议,同时也会兼容支持http协议。如果感兴趣,就跟着小编一起coding吧。

    3.2 通信层架构设计

    前面说了,我们是站在巨人的肩膀上的,根据dubbo的设计思路和我们的目标,我们也来画一张图。

    在这里插入图片描述
    我们的最终架构如上图。

    作用
    serialize序列化协议层,包含了多种序列化协议
    codec数据解码器和编码器的具体实现层
    exchangeAPI交换层,业务层API和通信层API交换数据的地方,负责将业务数据转换成二进制数据发送,也负责将二进制数据转换成业务数据返回
    model基础数据模型
    business提供给开发者用来实现业务的api
    apiFluent 风格的api, 这种风格的好处是不需要记住接下来的步骤和方法

    3.3 工程结构

    在这里插入图片描述

    为了符合前面我们定的目标,所以我们要有一个大的工程。

    项目名职责
    mojito-net底层通信模块
    mojito-rpcrpc模块
    mojito-spring-boot-starterspringboot自动化配置

    由此我们的项目诞生了。下一篇我们就开始手撸代码吧。

    .
    ├── README.md
    ├── mojito-net
    │   ├── pom.xml
    │   └── src
    │       ├── main
    │       │   ├── java
    │       │   └── resources
    │       └── test
    │           └── java
    ├── mojito-rpc
    │   ├── pom.xml
    │   └── src
    │       ├── main
    │       │   ├── java
    │       │   └── resources
    │       └── test
    │           └── java
    ├── mojito-spring-boot-starter
    │   ├── pom.xml
    │   └── src
    │       ├── main
    │       │   ├── java
    │       │   └── resources
    │       └── test
    │           └── java
    └── pom.xml
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
  • 相关阅读:
    AI系统ChatGPT程序源码+AI绘画系统源码+支持GPT4.0+Midjourney绘画+已支持OpenAI GPT全模型+国内AI全模型
    猿创征文|大数据开发必备的数据采集工具汇总
    java计算机毕业设计ssm魔术教学网站k304y(附源码、数据库)
    pytorch gpu安装
    【21天学习挑战赛】希尔排序
    TM-30 计算软件 (Excel图表显示版本)
    一种ESDF地图实现方法:FIESTA
    2023东华理工大学计算机考研信息汇总
    网页开发——淘宝首页导航
    使用Python为Word文档增添水印:文字或图片水印轻松插入!
  • 原文地址:https://blog.csdn.net/Message_lx/article/details/125903177