指尖代码 发表于 2021-9-22 00: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的原因。
https://p9.toutiaoimg.com/large/pgc-image/06c1707a143c46128f1e1ee18bb3d8ea

可以通过@SPI注解将接口声明由Dubbo的SPI机制加载实现类。
https://p5.toutiaoimg.com/large/pgc-image/f72430efa8a0411eae0d1d8afed6d420
Dubbo如何实现SPI?

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

下面分析ExtensionLoader构造方法,假如type类型不为ExtensionFactory则先实行ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()
https://p6.toutiaoimg.com/large/pgc-image/2c0855855a9a457bb396c0eec902305b

getAdaptiveExtension首先从缓存中获取实例,没有则通过createAdaptiveExtension创建实例。
https://p26.toutiaoimg.com/large/pgc-image/3db00203f381414aa93cb2568aa2951d

createAdaptiveExtension首先通过getAdaptiveExtensionClass().newInstance()创建实例,再通过injectExtension包装。
https://p9.toutiaoimg.com/large/pgc-image/7dcd876bfcf64bf886fbd69da195128b

getAdaptiveExtensionClass首先通过getExtensionClasses获取Class,找不到则通过createAdaptiveExtensionClass创建。
https://p26.toutiaoimg.com/large/pgc-image/a0e765927d9845798ab7cb085cf9179b

getExtensionClasses首先通过缓存获取Class获取不到则通过loadExtensionClasses方法获取,获取后放到classesMap中。
https://p26.toutiaoimg.com/large/pgc-image/0d7bede43d904a55bd5917bb0a34cf9c

loadExtensionClasses首先获取SPI注解的属性值放到缓存中,下面通过loadDirectory从配置文件中加载Class,主要从META- INF/dubbo/、META-INF/services/、META-INF/dubbo/internal几个目次下加载文件。
https://p3.toutiaoimg.com/large/pgc-image/1c684565742a4ecdae60296009895dfa


https://p26.toutiaoimg.com/large/pgc-image/a30c90f9182c4c5cb4d111ec910e1320

根据dir和type作为文件名加载资源,并通过loadResource加载类的信息并放到extensionClasses中。
https://p5.toutiaoimg.com/large/pgc-image/6b5341c6c3c54cb983d942395fbe3e4b

loadResource中读取文件并解析文件内容获取name和接口实现类的名称,下面通过loadClass加载。
https://p9.toutiaoimg.com/large/pgc-image/6fbd102070af4227a8c141339cae80cf

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

下面在回到getAdaptiveExtensionClass方法中,首先在缓存中查找,找不到则会通过createAdaptiveExtensionClass创建Class。
https://p3.toutiaoimg.com/large/pgc-image/811598a8b25240e8ae873171882ccfa8

createAdaptiveExtensionClass首先根据type和SPI配置的value的值生成Adaptive包装类并编译为Class,也就是说我们获取的类型不是配置的实现类对象,而是Adaptive包装类对象。
https://p5.toutiaoimg.com/large/pgc-image/e10e8db6efa64ef1919d4d92f20b6048

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

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

refer方法逻辑雷同,只是最后调用实现类的refer方法。
https://p6.toutiaoimg.com/large/pgc-image/ddc6a9abdc4045ccb7c1ac24adce6b29

下面我们再回到createAdaptiveExtension方法中,通过getAdaptiveExtensionClass()已经拿到了动态创建的Adaptive类并通过newInstance创建对象,下面通过injectExtension完成依赖注入。
https://p9.toutiaoimg.com/large/pgc-image/08ea0e4f149e4ae58fd277b0620646a2
如何实现IOC?

injectExtension获取setter方法,并通过objectFactory.getExtension(pt, property);获取必要注入的对象,通过反射调用setter方法完成依赖注入。
https://p6.toutiaoimg.com/large/pgc-image/57458ba2c5b349dfb4b1ffd5ebb38048

objectFactory可能是下面三种实现类,也就是说除了可以通过Spi获取注入的对象也可以从spring中获取注入对象。而AdaptiveExtensionFactory则会循环调用多个factory获取对象。
https://p26.toutiaoimg.com/large/pgc-image/defc1f9c39c94f5aa746bbecaa96286c

一般objectFactory经过初始化后会封装为AdaptiveExtensionFactory并且包罗了spi和spring两个工厂,也就是说默认会通过spi和spring两种方式加载必要注入的对象。
https://p6.toutiaoimg.com/large/pgc-image/426dbf3968fa44e1b15918ef9f146291
为什么可以得到AdaptiveExtentionFactory?


<span style="letter-spacing: 1px;">在容器启动时,会解析<span style="color: #858080; --tt-darkmode-color: #858080;">
页: [1]
查看完整版本: Dubbo 源码分析