dubbo 学习(二)-- 简单实现远程方法调用

参考博客

前言

在学习dubbo过程中,经常有“我要学习什么的想法”,经常有看完一部分不知道后面要干嘛的时候。总的来说感觉自己缺少“dubbo能干什么?”的明确答案,所以在学习的时候就缺乏学习路线,这也跟自己长期的学习习惯有关:我要学习A技能,上网搜索 “A技能教程”或者“从零开始学A”。这样自己的学习完全依赖他人的总结,所以导致学习的成果同样依赖博客的质量,这就是高耦合啊同学们!!!我的学习质量为什么要依赖他人的学习成果。希望从今天开始改变自己的学习方式,从dubbo开始.

RPC

dubbo是一个RPC框架,在学习这个框架之前我们需要先明白什么是RPC,为什么需要RPC框架,怎么实现RPC框架(what why how)。

RPC是Remote Procedure Call,字面意思就是“远程过程调用”,翻译为“远程程序调用”可能更符合我们程序员。它的功能就是可以在A机器上访问B机器上的方法。

那么为什么需要RPC,随着业务量扩大,单机系统拆分成集群,为了维护性和高可用性的系统服务化,都需要RPC来实现。那么现在对RPC有了大致了解,也知道为什么要用RPC了,但是RPC框架是什么鬼,它有啥用?那么这就要从如何实现RPC讲起了。

RPC框架结构

我们先来想想如何实现一次远程调用,既然是远程调用,首先肯定要处理网络问题,我们可以使用现有协议比如http,或者我们自定义协议;网络问题解决后就要传输数据了,客户端调用服务端方法,需要知道对方地址(ip),调用的方法地址(接口名称,方法名称),参数等。传输这些数据之前就需要对数据进行序列化操作,相对的接收数据后需要反序列化。盗用大佬的一副图片
在这里插入图片描述
以及大佬说的:
1)服务消费方(client)调用以本地调用方式调用服务;

2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;

3)client stub找到服务地址,并将消息发送到服务端;

4)server stub收到消息后进行解码;

5)server stub根据解码结果调用本地的服务;

6)本地服务执行并将结果返回给server stub;

7)server stub将返回结果打包成消息并发送至消费方;

8)client stub接收到消息,并进行解码;

9)服务消费方得到最终结果。
RPC的目标就是要2~8这些步骤都封装起来,让用户对这些细节透明。

后面我会按照大佬的逻辑实现一个简单rpc框架。

简单通信

首先是两个项目通过socket的通信,相信大家之前都写过类似的轮子,这里就不贴代码;

特定服务调用

既然两个服务可以通过网络互相通信,那么我们完全可以在客户端发送需要调用的服务类信息、方法信息、参数等。
调用的服务

public interface DemoService {

    String sayHi(String name);
}

客户端调用代码如下

public class ClientApp {

    public static void main(String[] args) {

        try {
            RPCClient.start();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        DemoService service = ServiceFactory.createService("demo");
        System.out.println(service.sayHi("haha"));
    }
}

start是启动了网络访问;后面我们需要假装给接口一个实现类,然后由这个实现类执行目标方法。
根据我们前面的理论,我们需要一个代理类来假装实现类,完成访问远端方法的责任,所以这里我们使用一个静态代理实现(为了简单)。

public class DemoServiceProxy implements DemoService {

    public String sayHi(String name){

        String msg = "com.tiger.dubbo.api.DemoService-sayHi-java.lang.String-" + name;
        try {
            return (String) RPCClient.sendMsg(msg);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

代理类非常简单;msg中的信息是传给服务端的,服务端会解析信息中的内容做相应的处理,这里我们简单处理,定义参数间用“-”隔开,第一个为服务类名称,第二个为方法名,第三个为参数类,第四个为参数值(对,只支持一个参数),这就相当于一个简单的协议。

服务端这边也很简单,根据协议解析信息,并做处理代码如下:

public static Object handleMsg(String msg)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
            InstantiationException, InvocationTargetException {

        String[] msgArr = msg.split("-");
        String klassName = msgArr[0];
        if ("com.tiger.dubbo.api.DemoService".equals(klassName))
            klassName = "com.togo.service.DemoServiceImpl";
        Class klass = Class.forName(klassName);
        Class param = Class.forName(msgArr[2]);
        Method method = klass.getMethod(msgArr[1], param);

        return method.invoke(klass.newInstance(), msgArr[3]);
    }

看到我的实现类获取方式有没有某个部位突然发紧。Orz

根据我们的协议,一些信息,并执行对应方法,将信息返回。

至此有翔以来最吊的rpc完成了~~撒花~~

当然后续会继续完善,并对照dubbo等框架学习~作者还是很认真的 ~.~

完整代码

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章