简易版 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工作的流程,比只看概念具体一点,方便理解

相关推荐
xcyxiner2 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner3 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner3 天前
DicomViewer (添加模型类)3
qt
xcyxiner4 天前
DicomViewer (目录调整) 2
qt
xcyxiner4 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
霜落长河5 天前
抛弃TCP改用UDP,HTTP3怎么了?
http
桥田智能6 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
之歆6 天前
现代 HTTP 客户端深度解析:Fetch 与 Axios
chrome·网络协议·http
小胖xiaopangss6 天前
BRpc使用
c++·rpc
森G6 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt