最近准备对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,并通过saveInExtensionClass将name和class的值保存到extensionClasses中。
下面在回到getAdaptiveExtensionClass方法中,首先在缓存中查找,找不到则会通过createAdaptiveExtensionClass创建Class。
createAdaptiveExtensionClass首先根据type和SPI配置的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并且包罗了spi和spring两个工厂,也就是说默认会通过spi和spring两种方式加载必要注入的对象。
为什么可以得到AdaptiveExtentionFactory?
<span style="letter-spacing: 1px;">在容器启动时,会解析<span style="color: #858080; --tt-darkmode-color: #858080;"> |