一、背景
前段时间了解了泛化调用这个玩意儿,又想到自己之前写过一个RPC框架(参考《手写一个RPC框架》),于是便想小试牛刀。
二、泛化调用简介
什么是泛化调用
泛化调用就是在不依赖服务方接口jar包的情况下进行调用,包括对调用方法的泛化、参数的泛化和返回值的泛化。
泛化调用的使用场景
常规的PRC调用都是客户端依赖服务端提供的接口jar包,然后利用动态代理技术,像调用本地方法一样调用远程方法,但是有些场景下客户端无法依赖jar包,也要调用远程方法,这时就需要用到泛化调用了。
常规的使用场景包括:
-
网关,如果服务内部调用使用RPC协议,对外暴露HTTP接口,这时就需要在网关做协议转换(HTTP转RPC协议),但是网关不可能依赖所有接口的jar包,只能采用泛化调用。
-
测试平台
实现方案
实现方案有两种:
- 第一种是基于Java Bean的泛化调用,例如dubbo的泛化调用会将参数转换成JavaBeanDescriptor,代码可以参考GenericFilter。
- 第二种是基于序列化中间体的泛化调用,如sofa-rpc,使用了sofa-hessian序列化框架,sofa-hessian是在hessian序列化框架基础上进行二次开发的,抽象出了序列化中间体,如GenericObject、GenericMap、GenericArray等。
三、开发实现
3.1 类图
客户端
服务注册和发现
3.2 数据传输过程
3.3 客户端实现
首先定义一个泛化调用接口GenericService
java
复制代码
public interface GenericService { /** * 泛化调用 * @param methodName * @param parameterTypeNames * @param args * @return */ Object $invoke(String methodName, String[] parameterTypeNames, Object[] args); }
注意: 这里参数类型parameterTypeNames用的是参数类型名称数组而不是Class数组,是因为泛化调用客户端可能不存在对应的类。
默认实现类DefaultGenericService
java
复制代码
/** * @Author: Ship * @Description: * @Date: Created in 2023/6/15 */ public class DefaultGenericService implements GenericService { private MethodInvoker methodInvoker; priva