要想先理解远程调用,那么首先必不可少的就是理解本地调用

本地调用

我们当初的单体应用项目所有的请求就是本地调用。例如:将一个学生信息进行修改,首先前台http请求后端接口,调用当前项目所提供的功能规范进行传参,最后实现调用修改功能

远程调用

在上诉的过程中,本地http请求当前项目提高的学生修改功能,但是真正的更改功能服务在另一个项目中运行,也就是说你真实要访问的服务在另一个主机,你在当前请求的接口功能修改其实就是涉及了RPC的一次调用过程,先本地请求调用传参,然后由本地服务向另一个主机发送数据请求,接受server端的数据返回,当前的请求就相当于是Client端。

frida Rpc 调用 rpc调用代码_java


在微服务的设计中,一个服务A如果访问另一个Module下的服务B,可以采用HTTP REST传输数据,并在两个服务之间进行序列化和反序列化操作,服务B把执行结果返回过来。

frida Rpc 调用 rpc调用代码_io_02

为什么不直接进行Http

当大家看了上面的远程调用的过程会想,client端为什么不直接远程http请求服务端呢?主要两个原因
1.HTTP在应用层中完成,整个通信的代价较高,远程过程调用中直接基于TCP进行远程调用,数据传输在传输层TCP层完成,更适合对效率要求比较高的场景,RPC主要依赖于客户端和服务端之间建立Socket链接进行,底层实现比REST更复杂。
2.由于采用了RPC,各个厂商为适应不同的平台而遵循这个RPC规范,中间具体调用传输,采取什么序列化技术由他们自己选择,所有就有了很多RPC框架,如dubbo

下面会附送自定义RPC实现的过程源码,建议不懂的大家可以先了解下 Socket io 网络这些基本概念

Server端

frida Rpc 调用 rpc调用代码_java_03

业务逻辑代码

package com.demo.provider;

import rpcservice.RpcRequest;

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;

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()  {
        ObjectOutputStream objectOutputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            //获取client 请求的输入流,获取相关参数信息
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            //将流信息转换对象
            RpcRequest request = (RpcRequest)objectInputStream.readObject();
            //执行业务逻辑
            Object result =invoke(request);
            //将result返回结果 返回client
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(result);
            objectOutputStream.flush();
        } catch (IOException | ClassNotFoundException | NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException 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 request) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        //通过反射 执行方法
        String className = request.getClassName();
        Object[] parameters = request.getParameters();
        Class[] types = new Class[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            types[i]=parameters[i].getClass();
        }
        Class<?> aClass = Class.forName(className);
        Method method = aClass.getMethod(request.getMethodName(),types);
        Object result = method.invoke(service, parameters);
        return result;
    }
}

frida Rpc 调用 rpc调用代码_io_04

Client端

frida Rpc 调用 rpc调用代码_socket_05


frida Rpc 调用 rpc调用代码_frida Rpc 调用_06


jdk动态代理

frida Rpc 调用 rpc调用代码_rpc_07


frida Rpc 调用 rpc调用代码_rpc_08

Client业务逻辑执行

package com.rpc.client;

import rpcservice.RpcRequest;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

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){
        Object result = null;
        ObjectInputStream objectInputStream = null;
        ObjectOutputStream objectOutputStream = null;
        try {
            //client请求远程服务器
            Socket socket = new Socket(host, port);
            //传输数据
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(request);
            objectOutputStream.flush();
            
            //接收Server端返回的参数
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            result = objectInputStream.readObject();
        } catch (IOException | ClassNotFoundException 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();
                }
            }
        }
        return result;
    }
}