基于netty仿Dubbo实现自己的RPC框架

323 阅读3分钟

总体架构

  • rpc-api:客户端和服务端的公共调用接口
  • roc-common: 项目中通用的一些枚举类和工具类
  • rpc-core: 框架的核心实现
  • test-client: 测试用的客户端项目
  • test-server: 测试用的服务端项目

一个简单的实现版

RPC框架的原理:

服务端和客户端都可以访问到通用的接口,只有服务端中有这个接口的实现类,客户端通过网络传输的方式调用这个接口,告诉服务端我需要这个接口,服务端收到请求后找到这个实现类并执行,将生成的结果给客户端调用的接口的返回值。

需要思考的问题:

  • 客户端怎么知道服务端的地址
  • 客户端怎么告诉服务端要调用的接口
  • 客户端怎么传递参数
  • 客户端只有接口怎么生成实现类

假设客户端已知服务端的地址,完成一个最简单的实现

通用接口

hello方法需要传递一个对象HelloObject

定义如下

注意,Hello Object这个对象要实现Serializable这个序列化接口, ,因为调用的过程中要从客户端发送给服务端

在服务端实现这个接口的实现类

简单的实现,返回一个message字符串

传输格式

服务端需要哪些信息,才能唯一确定服务端要调用的接口的方法呢

  • 接口名字
  • 方法名字
  • 重载原因:需要方法的所有参数类型
  • 客户端调用方法时的实际参数值

当服务端知道这4个条件,就可以找到方法并进行调用了

我们将这4个条件写进一个对象RpcRequest中,到时候传输时传输这个对象就够了

当服务端调用发放成功后,需要给客户端返回哪些信息

  • 调用成功:需要返回值
  • 调用失败: 失败的信息

客户端的实现:动态代理

因为客户端并没有接口的具体实现类,没有办法直接生成实例对象。可以动态代理的方式生成实例,并生成RpcRequest对象发送给服务端

使用JDK动态代理,需要实现 InvocationHandler 接口

传递的host和post指明服务端的位置,getProxy方法生成代理对象

实现InvocationHandler需要实现invoke()方法,指明代理对象方法被调用时的动作,这里我们应该生成RpcRequest对象并发送出去,然后返回从服务端接收的结果即可

RpcClient对象作用:将一个对象发送出去,并接收返回的对象

使用java序列化,通过socket进行传输。创建一个socket获取Object OutputStream 对象,然后将要发送的对象发送出去即可,接收时获取ObjectInputStream对象.readObject方法可以获得一个对象

服务端的实现:反射调用

使用ServerSocket监听某个端口,循环接收连接请求,如果新来一个来连接就新建一个线程处理调用,创建线程采用线程池方法

其中,通过class.getMethod方法,传入方法名和方法参数类型即可获得Method对象。如果你上面RpcRequest中使用String数组来存储方法参数类型的话,这里你就需要通过反射生成对应的Class数组了。通过method.invoke方法,传入对象实例和参数,即可调用并且获得返回值。