Dubbo学习-理解动态代理
Dubbo学习-理解动态代理
在之前的一篇post中了解了spring可扩展的XML配置是怎么一会事,接下来继续研究dubbo consumer端如何解析service并执行远程调用。
本次研究目标
- 代理如何创建的。仅仅只是配置了
<dubbo:reference interface="x.y.z.ServiceInterface" id="serviceId"/>
并将其交给了spring container,然后直接注入并使用该接口的方法就可以完成调用了,然而我并没有为该接口实现具体的类,how does it works? 远程调用如何执行的。假设已经有了具体的实现类,怎么实现远程调用的呢,Thingking?由于第一个分析就很长,这个目标列入下一次分析。
预备知识
为了顺利的研究上述两个目标,需要了解以下知识:
- SPI. 官方教程。用于服务扩展。
- Netty. User Guide。用于远程调用。
- Javassist. 官方Tutorial。动态类生成。
How to dig in?
从何处入手是个问题,我的习惯是顺藤摸瓜,所以从service被注入开始:
dubbo service配置:
|
|
Service注入:
|
|
当使用这个demoService
的时候可以肯定的是一定有个DemoService的具体实现可供使用,DubboNamespaceHandler
中有这样一段代码:
|
|
解析上面配置在namespace dubbo下的reference。DubboBeanDefinitionParser
相关代码如下:
|
|
上面两个关键的属性值id,interface都设置在了bean上,后面会用到。ReferenceConfig中的settter:setInterface用来设置interface:
|
|
参考ReferenceBean Hierarchy:
ReferenceBean中包含以几个两个方法:
|
|
如此,重点关注ReferenceConfig#get(),follow up:
|
|
进入init():
|
|
进入createProxy(Map):
|
|
到这里已经知道代理是由ProxyFactory创建了,接下重点看看ProxyFactory.
ProxyFactory
ProxyFactory Hierarchy:
AbstractProxyFactory
|
|
JavassistProxyFactory
|
|
getProxy
的相关代码:
|
|
动态类的实现:
|
|
toClass()
为ClassGenerator的方法,实现也是通过javassist生成动态类。 这儿返回的是Proxy的子类实例。JavassistProxyFactory的getProxy中Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
这儿的newInstance()就属于这个子类实例。该方法的定义:
|
|
再来看看InvocationHandler的实现:
|
|
看到这儿可能还有点迷糊,invoke是在哪里调用的呢?回头看看动态类生成部分有这样一段代码:
code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
这就将代理调用衔接起来了。看起来可能有点抽象,待下面来试验一把。
试验
DemoService.java
|
|
Main.java
|
|
在ClassGenerator
中 toClass返回前加入以下代码:
|
|
debug一下main,在动态生成类的时候将类写入文件中,结果如下:
DemoService的实现:
|
|
Proxy的子类:
|
|
其中DC接口只是一个标识接口,表示该类是动态生成的。这样看起来就比较清晰明了了。下面再来看看jdk的proxy。
JdkProxyFactory
相关代码如下:
|
|
可以看到Proxy.newProxyInstance
直接使用的是JDK的动态代理机制,因此就不再跟下去了。
总结
至此,对dubbo本地动态代理有一个清晰的理解了,总的来说一路顺藤摸瓜还算顺畅。对于选择哪一中方式作为生产使用,Dubbo推荐使用Javassist的代理机制,因为jdk原生的动态代理性能较差,生产环境不宜使用。