关于dubbo的泛化调用,很多人都用过,今天我们从原理层面说下dubbo的泛化调用。此文适合有一定dubbo源码基础的人,如果没有的话,先去熟悉下再来看此篇文章

一、使用

关于dubbo泛化调用的使用方式如下:

public Object genericInvoke(String interfaceClass, String methodName, List<Map<String, Object>> parameters){

ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
reference.setApplication(application);
reference.setRegistry(registry);
reference.setInterface(interfaceClass); // 接口名
reference.setGeneric(true); // 声明为泛化接口
reference.setVersion("1.0.0");
// reference.setCheck(false);

//ReferenceConfig实例很重,封装了与注册中心的连接以及与提供者的连接,
//需要缓存,否则重复生成ReferenceConfig可能造成性能问题并且会有内存和连接泄漏。
//API方式编程时,容易忽略此问题。
//这里使用dubbo内置的简单缓存工具类进行缓存

// ReferenceConfigCache cache = ReferenceConfigCache.getCache();
// GenericService genericService = cache.get(reference);
GenericService genericService = reference.get();

// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用

int len = parameters.size();
String[] invokeParamTyeps = new String[len];
Object[] invokeParams = new Object[len];
for(int i = 0; i < len; i++){
invokeParamTyeps[i] = parameters.get(i).get("ParamType") + "";
invokeParams[i] = parameters.get(i).get("Object");
}
return genericService.$invoke(methodName, invokeParamTyeps, invokeParams);
}

上面的方法就是
1.通过registryConfig和applicationConfig生成RefrenceConfig。
2.通过refrenceConfig的get()方法获取GenericService。
3.通过genericService的$invoke方法去调用dubbo。

二、遇到的问题

有些人遇到问题可能就是在获取GenericService这一步。

GenericService genericService = reference.get();

要么获取不到,要么获取超时。我们一步步跟这源码看下

三、源码解析

在get()方法中,会通过ReferenceConfig中的CreateProxy方法中的refer方法去获取引用:

invoker = refprotocol.refer(interfaceClass, urls.get(0));

refer方法获取真正的执行类

在refer方法中,获取真正的执行类,refprotocol是通过ExtensionLoader获取的,你可以声明自己的,一般用默认的就可以。默认的会走到RegistryProtocol的doRefer方法。然后通过RegistryDiretory的subscribe方法进行注册并在之后通过其refreshInvoker方法刷新提供者。所以ReferenceConfig中包含提供者的路由信息。如果最后找不到泛化调用的GenericService都是因为匹配提供者失败造成的,沿着这块代码去寻找一般都可以找到错误原因。
下面一张序列图,简略流程:


ReferenceConfig RegistryProtocol RegistryDirectory get(),createProxy() refer() subscribe() refreshInvoker() ReferenceConfig RegistryProtocol RegistryDirectory