RPC 框架

RPC 概念

RPC(Remote Procedure Call Protocool)远程过程调用。
为什么用RCP
各个模块可能部署在不同的主机上(主要的原因是不在一个内存空间,不能直接调用),需要远程通信访问,通过HTTP或者RPC的方式
调用的流程
1、解决通信问题,即建立TCP链接,通过链接进行数据传输
2、解决寻址问题,如何寻找B服务器上被调用的方法,可以理解为对外暴露方法的方式
3、客户端序列化传输到服务器
4、服务器反序列化解析处理结果,序列化返回
5、客户端反序列化解析结果
流行的RPC框架
Dubbo、Thrif(跨语言)、WebService(基于SOAP协议)、Hessian、grpc都是基于RPC原理实现的

手写RPC框架

设计模块

客户端和服务端都可以分成4层,最底层是socket接受发送请求,上面一层是序列化和反序列化,再往上是代理层,最顶端是用户调用层

涉及到的技术

1、通信(TCP协议)
2、序列化和反序列化,回顾之前的如(java原生方法,avro,protobuf,json,xml)
3、IO(BIO/NIO/AIO)
4、反射
5、代理
6、暴露服务:ip/端口/目标类/参数,如WebService对应的wsdl,dubbo对应//url

具体实现

创建一个两个maven项目rpc-server/rpc-client
server有两个模块api和provider,api对外提供接口,provider发布服务

破产版RPC

服务端

在这里插入图片描述
api
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190701094047785.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hleWFuZmVuZzIy,size_16,color_FFFFFF,t_70
在这里插入图片描述
RpcRequest

public class RpcRequest implements Serializable
{
    private String className;

    private String methodName;

    private Object[] parameters;

    public String getClassName()
    {
        return className;
    }

    public void setClassName(String className)
    {
        this.className = className;
    }

    public String getMethodName()
    {
        return methodName;
    }

    public void setMethodName(String methodName)
    {
        this.methodName = methodName;
    }

    public Object[] getParameters()
    {
        return parameters;
    }

    public void setParameters(Object[] parameters)
    {
        this.parameters = parameters;
    }

    @Override
    public String toString()
    {
        return "RpcRequest{" + "className='" + className + '\'' + ", methodName='" + methodName + '\'' + ", parameters=" + Arrays.toString(parameters) + '}';
    }
}

provider
在这里插入图片描述
依赖api
在这里插入图片描述
provider的主要功能
开启一个线程池不断的处理客户端的请求
启动服务App App

 public static void main(String[] args)
    {
        HelloService service = new HelloServiceImpl();
        RpcProxyServer proxyServer=new RpcProxyServer();
        proxyServer.publiser(service,8011);
    }

代理服务 RpcProxyServer

1、线程池:

//创建线程池
ExecutorService threadPool = Executors.newFixedThreadPool(5);

2、循环阻塞

serverSocket = new ServerSocket(port);
while(true)
{
 	Socket socket = serverSocket.accept();
 	threadPool.execute(new ProcessorHandler(socket,service));
}

3、处理输入输出流的线程 ProcessorHandler

package com.gupao.rpc;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;

/**
 * @Autor : heyanfeng22
 * @Description :
 * @Date:Create:in 2019/6/28 15:12
 * @Modified By:
 */
public class ProcessorHandler implements Runnable
{
    private Socket socket;

    private Object service;

    public ProcessorHandler(Socket Socket,Object service)
    {
        this.socket = Socket;

        this.service = service;
    }

    @Override
    public void run()
    {
        //处理请求
        ObjectInputStream objectInputStream=null;
        ObjectOutputStream objectOutputStream=null;

        try
        {
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject();
            //反射调用本地服务
            Object result=invoke(rpcRequest);

            //返回
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(result);
            objectOutputStream.flush();

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (objectInputStream!=null)
            {
                try
                {
                    objectInputStream.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }

            if(objectOutputStream!=null)
            {
                try
                {
                    objectOutputStream.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }

        }

    }

    private Object invoke(RpcRequest rpcRequest) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException
    {
        String className = rpcRequest.getClassName();
        String MethdName = rpcRequest.getMethodName();
        Object[] parameters = rpcRequest.getParameters();//拿到请求参数

        //获得每个参数的类型
        Class<?>[] types = new Class[parameters.length];

        for (int i=0;i<parameters.length;i++)
        {
            types[i] = parameters[i].getClass();
        }

        Class clazz = Class.forName(className);

        Method method = clazz.getMethod(MethdName,types);

        Object result = method.invoke(service,parameters);

        return result;
    }
}

客户端

在这里插入图片描述
依赖api
在这里插入图片描述
客户端访问 App

public static void main(String[] args)
    {
        //通过代理类调用服务
        RpcProxyClient proxyClient = new RpcProxyClient();

        HelloService service = proxyClient.createClient(HelloService.class,"localhost",8011);

        String result = service.sayHello("哈哈哈");

        System.out.println(result);

    }

代理类 RpcProxyClient

public class RpcProxyClient
{
    public <T> T createClient(Class<T> inerfaceClazz,String ip,int port)
    {
        return (T)Proxy.newProxyInstance(inerfaceClazz.getClassLoader(),new Class<?>[]{inerfaceClazz},new RemoteInvocationHandler(ip,port));

    }
}

代理实现类 RemoteInvocationHandler

public class RemoteInvocationHandler implements InvocationHandler
{
    private String host;

    private int port;

    public RemoteInvocationHandler(String host, int port)
    {
        this.host = host;
        this.port = port;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        //请求会进入到这里
        System.out.println("come in");

        //在这里处理请求
        //请求数据的包装
        RpcRequest rpcRequest=new RpcRequest();
        rpcRequest.setClassName(method.getDeclaringClass().getName());
        rpcRequest.setMethodName(method.getName());
        rpcRequest.setParameters(args);
        //远程通信
        RpcNetTransport netTransport=new RpcNetTransport(host,port);
        Object result=netTransport.send(rpcRequest);

        return result;
    }
}

具体请求类 RpcNetTransport

public class RpcNetTransport
{


    private String host;
    private int port;

    public RpcNetTransport(String host, int port) {
        this.host = host;
        this.port = port;
    }



    public Object send(RpcRequest request){
        Socket socket=null;
        Object result=null;
        ObjectOutputStream outputStream=null;
        ObjectInputStream inputStream=null;

        try {
            socket=new Socket(host,port); //建立连接

            outputStream =new ObjectOutputStream(socket.getOutputStream());//网络socket
            outputStream.writeObject(request); //序列化()
            outputStream.flush();

            inputStream=new ObjectInputStream(socket.getInputStream());
            result=inputStream.readObject();


        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            if(inputStream!=null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outputStream!=null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;

    }
}

运行
服务端收到请求:
在这里插入图片描述
客户端收到回应:
在这里插入图片描述
到这里破产版的RPC框架就写完了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值