简易版 RPC 框架实现 1.0 -http实现

RPC 是"远程过程调用(Remote Procedure Call)"的缩写形式,比较通俗的解释是:像本地方法调用一样调用远程的服务。虽然 RPC 的定义非常简单,但是相对完整的、通用的 RPC 框架涉及很多方面的内容,例如注册发现、服务治理、负载均衡、集群容错、RPC 协议等,如下图所示:

简易 RPC 框架的架构图

本课时我们主要实现RPC 框架的基石部分------远程调用,简易版 RPC 框架一次远程调用的核心流程是这样的:

  1. Client 首先会调用本地的代理,也就是图中的 Proxy。
  2. Client 端 Proxy 会按照协议(Protocol),将调用中传入的数据序列化成字节流。
  3. 之后 Client 会通过网络,将字节数据发送到 Server 端。
  4. Server 端接收到字节数据之后,会按照协议进行反序列化,得到相应的请求信息。
  5. Server 端 Proxy 会根据序列化后的请求信息,调用相应的业务逻辑。
  6. Server 端业务逻辑的返回值,也会按照上述逻辑返回给 Client 端。

这个远程调用的过程,就是我们简易版本 RPC 框架的核心实现,只有理解了这个流程,才能进行后续的开发。

这个版本写的非常简单实用http协议模拟的rpc实现

  • provider 是服务提供方
  • consumer 是服务调用方
    其实这两个都不算rpc框架内容,是使用者真正的业务代码
  • common 把rpc相关的都放入这一个模块中了

代码比较简单我们就直接从下面两个方便进行分析了

服务提供方

java 复制代码
public class Provider {

    public static void main(String[] args) {
        Url url = new Url("localhost", 8099);
        //模拟远程注册中心
        RemoteMapRegister.regist(HelloService.class.getName(),url);
        //指明服务的实现类
        LocalRegister.regist(HelloService.class.getName(), HelloServviceImpl.class);
        //获取协议
        Protocal protocol = ProtoaclFactory.getProtocol();
        //启动 start
        protocol.start(url);
    }
}

URL 统一配置

比较简单不做赘述

远程注册中心

我们这个使用的内存+本地文件存储

java 复制代码
public static void regist(String interfaceName, Url url){
//        REGISTER.putIfAbsent(interfaceName, new ArrayList<>());
        List<Url> urls = REGISTER.get(interfaceName);
        if(urls == null){
            List<Url> objects = new ArrayList<>();
            objects.add(url);
            REGISTER.put(interfaceName, objects);
        }else {
            urls.add(url);
        }
        saveFile();
    }

服务的实现类

实现类方便服务调用方进行调用

java 复制代码
public class LocalRegister {

    private static Map<String, Class> map = new HashMap<>();
    public static void regist(String interfaceName, Class implClass){
        map.put(interfaceName,implClass);
    }

    public static Class get(String interfaceName){
        return map.get(interfaceName);
    }
}

代码中可以看出来非常简单,放到内存map中了

获取协议

其实说白了根据参数获取相关的协议实现

java 复制代码
public static Protocal getProtocol(){
        String name = System.getProperty("protocalName");
        if(name == null || name.equals("")) name = "http";
        switch (name){
            case "http":
                return new HttpProtoacl();
            case "dubbo":
                return new DubboProtocal();
            default:
                break;
        }
        return new HttpProtoacl();
    }

根据不同的协议我们开启不同的服务,供服务调用方进行调用

开启服务

//启动 start

protocol.start(url);

根据不同的协议进行开启服务

java 复制代码
 @Override
    public void start(Url url) {
        HttpServer httpServer = new HttpServer();
        httpServer.start(url.getHostName(),url.getPort());
    }

我这用的http服务,底层开启了一个tomcat服务

服务调用方

java 复制代码
public static void main(String[] args) {
        HelloService proxy = ProxyFactory.getProxy(HelloService.class);
        System.out.println(proxy.say("hellow"));
    }

服务调用方 生成代理

服务调用方拿不到提供方的实例因此只能通过代理的方式进行访问

java 复制代码
 public static <T> T getProxy(final Class interfaceClass){
       return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Invocation invocation = new Invocation(interfaceClass.getName(), method.getName(), method.getParameterTypes(), args);
                List<Url> urlList=RemoteMapRegister.get(interfaceClass.getName());
                Url url = SimpleLoadBalance.random(urlList);
                Protocal protocol = ProtoaclFactory.getProtocol();
                String result= protocol.send(url,invocation);
                return result;
            }
        });
    }

代理中做的事情

  1. 根据远程的注册中心获取URL,即配置信息
  2. 提供方可能存在多个实例, 因此是用负载均衡进行流量负载
  3. 根据协议,发送请求,这个地方我们发送请求没做任何逻辑,实际rpc这个地方会存在很多逻辑
  4. 获取到响应数据返回给调用方

总结

其实这个在一定意义上算不上rpc 框架, 只能说是帮我们简单的理解rpc工作的流程,比只看概念具体一点,方便理解

相关推荐
Mr.Q5 分钟前
OpenCV和Qt坐标系不一致问题
qt·opencv
重生之我是数学王子3 小时前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
----云烟----12 小时前
QT中QString类的各种使用
开发语言·qt
「QT(C++)开发工程师」18 小时前
【qt版本概述】
开发语言·qt
一路冰雨1 天前
Qt打开文件对话框选择文件之后弹出两次
开发语言·qt
老赵的博客1 天前
QT 自定义界面布局要诀
开发语言·qt
gma9991 天前
brpc 与 Etcd 二次封装
数据库·c++·rpc·etcd
码码哈哈0.01 天前
VSCode 2022 离线安装插件QT VSTOOl报错此扩展不能安装在任何当前安装的产品上。
ide·vscode·qt
feiyangqingyun1 天前
Qt/C++离线地图的加载和交互/可以离线使用/百度和天地图离线/支持手机上运行
c++·qt·qt天地图·qt离线地图·qt地图导航