一次完成的RPC调用链路记载

天才风云出我辈,一见00岁月枯!

学习之前我对Rpc调用链路的理解

用户A 去调用 用户B的一个服务
在这里插入图片描述

对应下面的例子:
首先B先定义接口,以及实现类

B目录结构:
在这里插入图片描述

B的接口
所属Module: rpc-api

public interface IHelloService {

    String sayHello(String value);
}
B的实现类
所属Module: rpc-provider
public class HelloServiceImpl implements IHelloService{

    @Override
    public String sayHello(String value) {

        System.out.println("我这里是服务提供者,我接收到了请求");
        return "小白: " + value;
    }
}

之后将服务提供者B中的rpc-api打包就可以了,将接口暴露出去

A的实现
String s = helloService.sayHello("啦啦啦,德玛西亚");// 类似于调用本地方法

下面我们来仔细了解下,具体的调用细节

在此之前,我们先提出几个问题

  • 1.服务提供者是怎么样把服务暴露出来,供其它用户调用的
  • 2.服务调用者是怎么样寻找到服务提供者的

我的理解

  • 1.所谓的服务暴露简单点来说就是让其他人来调用"我的服务",换句话说让别人找到我就可以了
  • 2.作为调用者我只需要找到服务提供者就可以了
  • 3.当然了,两者之间需要进行数据的交互,比如说参数的传递

那么下面我们就围绕着下面几点来进行论证和讨论

服务提供者对外提供服务
服务对外提供,我们的思路是: 通过Serversocket暴露一个端口,让其他服务来访问我们,代码如下: 

-- 对外提供Rpc服务
public class RpcProxyServer {

    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public void publisher(Object service, int port) {

        ServerSocket serverSocket = null;

        try {
            serverSocket = new ServerSocket(port);

            while (true) {

               final Socket socket = serverSocket.accept();

               executorService.submit(new ProcessHandler(socket,service));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

-- 服务处理
public class ProcessHandler implements Runnable {

    Socket socket;
    Object service;

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

    @Override
    public void run() {

        ObjectInputStream inputStream = null;

        ObjectOutputStream outputStream = null;


        try {

            inputStream = new ObjectInputStream(socket.getInputStream());
            RpcRequest request = (RpcRequest) inputStream.readObject();
            Object result = invoke(request);

            outputStream = new ObjectOutputStream(socket.getOutputStream());
            outputStream.writeObject(result);
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Object invoke(RpcRequest request) {

        try {

            Class clazz = Class.forName(request.getClassName());
            Method method = clazz.getMethod(request.getMethodName(), request.getTypes());
            Object[] parameters = request.getParameters();
            Object result = method.invoke(service, parameters);
            return result;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }
}

-- 启动服务

public class App 
{
    public static void main( String[] args ) {

        IHelloService service = new HelloServiceImpl();

        RpcProxyServer proxyServer = new RpcProxyServer();
        proxyServer.publisher(service,8888);
        System.out.println( "Hello World!" );
    }
}

我们来简述下上面服务暴露的过程: 
简单版本: ServerSocket服务端暴露服务,Server访问服务,没了
复杂版本: 
		1. 声明我们要对外暴露的服务: IHelloService service = new HelloServiceImpl();
		2. 创建一个服务发布对象:    RpcProxyServer proxyServer = new RpcProxyServer();
		3. 将服务发布出去:         proxyServer.publisher(service,8888);
		4. 
下面我们针对: proxyServer.publisher(service,8888);来仔细说说

public class RpcProxyServer {

    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public void publisher(Object service, int port) {

        ServerSocket serverSocket = null;

        try {
            serverSocket = new ServerSocket(port);

            while (true) {

               final Socket socket = serverSocket.accept();

               executorService.submit(new ProcessHandler(socket,service));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

仔细详解: 

 serverSocket = new ServerSocket(port);指出对外暴露的端口
 final Socket socket = serverSocket.accept(); 接收外部的请求,accept()为一个阻塞方法,这里为了接受多个请求,因此用了
 线程池
 ok,到了这一步,要明白一点,我们的服务一定对外提供完毕,当执行下面的时候,证明服务提供者已经接收到了外部的请求
 executorService.submit(new ProcessHandler(socket,service));
 下面我们来看看,这个ProcessHandler(socket,service)这个里面的实现

下面我们来分析下这一段代码

public class ProcessHandler implements Runnable {

    Socket socket;
    Object service;

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

    @Override
    public void run() {

        ObjectInputStream inputStream = null;

        ObjectOutputStream outputStream = null;

        try {

            inputStream = new ObjectInputStream(socket.getInputStream());
            RpcRequest request = (RpcRequest) inputStream.readObject();
            Object result = invoke(request);

            outputStream = new ObjectOutputStream(socket.getOutputStream());
            outputStream.writeObject(result);
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Object invoke(RpcRequest request) {

        try {

            Class clazz = Class.forName(request.getClassName());
            Method method = clazz.getMethod(request.getMethodName(), request.getTypes());
            Object[] parameters = request.getParameters();
            Object result = method.invoke(service, parameters);
            return result;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }
}
首先它实现了run()方法
先看这一块代码: 
inputStream = new ObjectInputStream(socket.getInputStream());
RpcRequest request = (RpcRequest) inputStream.readObject();
Object result = invoke(request);

这一段代码是: 读取请求过来的数据流

再看invoke()方法

    private Object invoke(RpcRequest request) {

        try {

            Class clazz = Class.forName(request.getClassName());
            Method method = clazz.getMethod(request.getMethodName(), request.getTypes());
            Object[] parameters = request.getParameters();
            Object result = method.invoke(service, parameters);
            return result;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }
em... 要是看不懂,我也没办法,这个就是反射调用,根据方法,参数等信息进行反射调用
调用之后返回结果

            outputStream = new ObjectOutputStream(socket.getOutputStream());
            outputStream.writeObject(result);
            outputStream.flush();
将数据返回给调用者
Ps: 我觉得我已经触摸到了某种感觉,比如说服务发现,服务注册,心跳监听等。。嘤嘤嘤

下面我们再说下服务调用者吧

重点看下面三行代码: 

		RpcProxyClient client = new RpcProxyClient();
        IHelloService helloService = client.clientProxy(IHelloService.class, "localhost", 8888);
        String s = helloService.sayHello("啦啦啦,德玛西亚");// 类似于调用本地方法

我们来分析下这三行代码:

1. RpcProxyClient client = new RpcProxyClient(); 创建一个远程访问对象,点进去看看

public class RpcProxyClient {


    public <T> T clientProxy(final Class<T> interfaceCls, final String host,int port) {

        return (T) Proxy.newProxyInstance(interfaceCls.getClassLoader(),
                new Class<?>[]{interfaceCls},
                new RemoteInvocationHandler(host,port));
    }
}

ok,注意一下传递的参数

a.IHelloService.class 这是一个class对象
b.一个host: localhost
c.一个端口号port: 8888
可以推断下,localhost + port是用来定位目标主机的,这个IHelloService我们可以用来定位我们要访问的
对象

IHelloService helloService = client.clientProxy(IHelloService.class, "localhost", 8888);

这个方法返回的是一个代理对象,没了
看最后一行代码
String s = helloService.sayHello("啦啦啦,德玛西亚");// 类似于调用本地方法
当我们调用这个方法的时候,他会调用RemoteInvocationHandler.invoke(Object proxy, 
Method method, Object[] args)方法,别问我为什么?问就是男人的第七感(以后可以说说)

invoke()方法里面有个: rpcNetTransport.send(request)
这个里面就是调用的具体细节了

    public Object send(RpcRequest request) {

        Socket socket = null;
        ObjectOutputStream outputStream = null;
        ObjectInputStream inputStream = null;
        try {
            socket = new Socket(host, port);
            outputStream = new ObjectOutputStream(socket.getOutputStream());
            outputStream.writeObject(request);
            outputStream.flush();

            inputStream = new ObjectInputStream(socket.getInputStream());
            Object o = inputStream.readObject();
            return o;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
跟我们猜想的一样。。没啥说的,看不懂的可以留言,有什么问题的话,大家一起讨论,下期再见!
。。反正我是会了
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值