创意电子

标题: Dubbo 源码分析 [打印本页]

作者: 指尖代码    时间: 2021-9-22 00:00
标题: Dubbo 源码分析
最近准备对Dubbo的历史毛病进行分析,但以为不懂Dubbo的设计和实现直接去分析毛病比较困难,以是在分析毛病前先分析Dubbo的源码及实现,值得一提的是Dubbo的官网也有非常详细的源码分析的过程。
SPI机制及实现

Dubbo的SPI是对JDK自身SPI的扩展实现,增加了IOC和AOP的功能,是Dubbo实现的核心,Dubbo SPI必要的配置文件放在/meta- inf/dubbo目次下,通过键值对的方式配置,如下所示:
adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactoryspi=org.apache.dubbo.common.extension.factory.SpiExtensionFactoryDubbo的SPI和JDK自身的SPI对好比下,这也是Dubbo没有选择使用JDK自带SPI的原因。

                               
登录/注册后可看大图


可以通过
@SPI注解将接口声明由Dubbo的SPI机制加载实现类。

                               
登录/注册后可看大图

Dubbo如何实现SPI?

ExtensionLoader是Dubbo
SPI实现的核心类,每个界说的spi的接口都会构建一个ExtensionLoader实例。一般通过ExtensionLoader.getExtensionLoader获取ExtensionLoader实例。
getExtensionLoader首先判断是否为接口类型并且由@SPI注解修饰,也就是说只有@SPI修饰的接谈锋会由Dubbo的SPI机制去寻找实现类。下面会通过EXTENSION_LOADERS寻找是否已经有loader的实例,没有的话会创建一个并添加到EXTENSION_LOADERS中。

                               
登录/注册后可看大图


下面分析
ExtensionLoader构造方法,假如type类型不为ExtensionFactory则先实行ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()

                               
登录/注册后可看大图


getAdaptiveExtension首先从缓存中获取实例,没有则通过createAdaptiveExtension创建实例。

                               
登录/注册后可看大图


createAdaptiveExtension首先通过getAdaptiveExtensionClass().newInstance()创建实例,再通过injectExtension包装。

                               
登录/注册后可看大图


getAdaptiveExtensionClass首先通过getExtensionClasses获取Class,找不到则通过createAdaptiveExtensionClass创建。

                               
登录/注册后可看大图


getExtensionClasses首先通过缓存获取Class获取不到则通过loadExtensionClasses方法获取,获取后放到classesMap中。

                               
登录/注册后可看大图


loadExtensionClasses首先获取SPI注解的属性值放到缓存中,下面通过loadDirectory从配置文件中加载Class,主要从META- INF/dubbo/META-INF/services/META-INF/dubbo/internal几个目次下加载文件。

                               
登录/注册后可看大图




                               
登录/注册后可看大图


根据dir和type作为文件名加载资源,并通过
loadResource加载类的信息并放到extensionClasses中。

                               
登录/注册后可看大图


loadResource中读取文件并解析文件内容获取name接口实现类的名称,下面通过loadClass加载。

                               
登录/注册后可看大图


loadClass中首先查抄clazz是否是type的实现类,再去检测clazz的接口是否有Adaptive注解存在的话放到将类放到cachedAdaptiveClass缓存中,下面再通过是否有参数为clazz的构造方法,有的话将clazz存到cachedWrapperClasses中,下面查看实现类是否有Extension注解,有的话取出这个注解的值并赋值给name。下面获取name的值,可以通过xxx,xxx,xx=xxx.com等形式传入多个name,并通过saveInExtensionClassnameclass的值保存到extensionClasses中。

                               
登录/注册后可看大图


下面在回到
getAdaptiveExtensionClass方法中,首先在缓存中查找,找不到则会通过createAdaptiveExtensionClass创建Class。

                               
登录/注册后可看大图


createAdaptiveExtensionClass首先根据typeSPI配置的value的值生成Adaptive包装类并编译为Class,也就是说我们获取的类型不是配置的实现类对象,而是Adaptive包装类对象。

                               
登录/注册后可看大图


生成代码的逻辑比较复杂,我们就不深入分析了,不外我们可以拿到生成的代码,可以看看生成的代码主要做了什么。首先它是type接口的实现类,假如接口中的方法没有通过
Adaptive修饰,则直接抛出异常。

                               
登录/注册后可看大图


对于
Adaptive注解修饰的方法则会生成实现,首先查抄Invoker的url是否为空,再获取协议信息,假如没有配置协议则默认使用dubbo协议,下面获取Protocol的实现类并实行实现类的export方法,实在也就是对export进行了一些包装,在实行export前加了一些验证逻辑。

                               
登录/注册后可看大图


refer方法逻辑雷同,只是最后调用实现类的refer方法。

                               
登录/注册后可看大图


下面我们再回到
createAdaptiveExtension方法中,通过getAdaptiveExtensionClass()已经拿到了动态创建的Adaptive类并通过newInstance创建对象,下面通过injectExtension完成依赖注入。

                               
登录/注册后可看大图

如何实现IOC?

injectExtension获取setter方法,并通过objectFactory.getExtension(pt, property);获取必要注入的对象,通过反射调用setter方法完成依赖注入。

                               
登录/注册后可看大图


objectFactory可能是下面三种实现类,也就是说除了可以通过Spi获取注入的对象也可以从spring中获取注入对象。而AdaptiveExtensionFactory则会循环调用多个factory获取对象。

                               
登录/注册后可看大图


一般objectFactory经过初始化后会封装为
AdaptiveExtensionFactory并且包罗了spispring两个工厂,也就是说默认会通过spispring两种方式加载必要注入的对象。

                               
登录/注册后可看大图

为什么可以得到AdaptiveExtentionFactory?


<span style="letter-spacing: 1px;">在容器启动时,会解析<span style="color: #858080; --tt-darkmode-color: #858080;">




欢迎光临 创意电子 (https://wxcydz.cc/) Powered by Discuz! X3.4