Dubbo-SPI源码分析

前言

本文接上文Dubbo-SPI机制,这里单独拎处这篇文章是不想让上文篇幅过长,因为过长的篇幅很难看下去!接着上文的Demo!如下!
在这里插入图片描述
上面demo中我们可以分为两块,一块是构建ExtensionLoader,也就是下面这块代码

ExtensionLoader<LoginService> extensionLoader = ExtensionLoader.getExtensionLoader(LoginService.class);

另一块是通过ExtensionLoader获取Extension,也就是getExtension()方法,代码如下!

LoginService wx = extensionLoader.getExtension("wx");

我在分析Dubbo-SPI源码的时候看了一些其他的文章,都是直接切入getExtension()方法来分析Dubbo-SPI机制的,就连Dubbo官方文档都是草草几句略过,既然还来了句简单!Dubbo官网文档Dubbo SPI 源码分析
在这里插入图片描述
没深入看还真的以为这个创建ExtensionLoader实例挺简单的,深入分析后发现其实在构建ExtensionLoader实例的时候就已经把整个SPI机制走完了。。。也就是getExtension()这个方法在构建的时候已经使用到了,那么本文就分为两块,一块是构建ExtensionLoader实例,另一块是获取Extension!

构建ExtensionLoader源码分析

基本介绍
这块逻辑其实是有点绕的
ExtensionLoader.getExtensionLoader
在这里插入图片描述
这里有三个判断,判断是否为空的、是否是接口、是否被SPI注解标记,如果不为空,是接口,且被SPI注解标记,那么就处理,否则一个异常送给控制台!判断完了后会在EXTENSION_LOADERS缓存中获取一下有没有这个类型的扩展点加载器,如果没有那么就创建一个,通过下面这行代码开始构造扩展点加载器(new ExtensionLoader(type))

EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));

new ExtensionLoader(type)
在这里插入图片描述
这行代码其实挺有意思的,同时也比较绕,此时进来的type为LoginService类型!那么下面这行代码做了三元运算!

objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());

此时type≠ExtensionFactory,那么会执行ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()方法,先执行的是前面部分也就是下面这行代码!标注前部分代码

ExtensionLoader.getExtensionLoader(ExtensionFactory.class)

这里其实又是调用了刚开始的getExtensionLoader方法,只不过是将type变为了ExtensionFactory
在这里插入图片描述

在这里插入图片描述
此时type为ExtensionFactory,那么满足三元运算前置条件,那么objectFactory就为null,然后将type为ExtensionFactory的扩展点加载器放入到EXTENSION_LOADERS缓存中
在这里插入图片描述
然后将type为ExtensionFactory的扩展点加载器返回给执行了前部分代码方法ExtensionLoader.getExtensionLoader(ExtensionFactory.class)的地方,也就是回到 标注前部分代码 接着执行后部分.getAdaptiveExtension()方法!

ExtensionFactory也被@SPI注解注释,说明他也是一个扩展点,从前面com.alibaba.dubbo.common.extension包的结构图中可以看到,dubbo内部提供了两个实现类:SpiExtensionFactory 和 AdaptiveExtensionFactory,实际上还有一个SpringExtensionFactory,不同的实现可以已不同的方式来完成扩展点实现的加载,这块稍后再来学习。从ExtensionLoader的构造函数中可以看到,如果要加载的扩展点类型是ExtensionFactory是,object字段被设置为null。由于ExtensionLoader的使用范围有限(基本上局限在ExtensionLoader中),因此对他做了特殊对待:在需要使用ExtensionFactory的地方,都是通过对应的自适应实现来代替。
默认的ExtensionFactory实现中,AdaptiveExtensionFactotry被@Adaptive注解注释,也就是它就是ExtensionFactory对应的自适应扩展实现(每个扩展点最多只能有一个自适应实现,如果所有实现中没有被@Adaptive注释的,那么dubbo会动态生成一个自适应实现类),也就是说,所有对ExtensionFactory调用的地方,实际上调用的都是AdpativeExtensionFactory,那么我们看下他的实现代码:

在这里插入图片描述
这也就是刚开始说得有点绕的地方!

从前面ExtensionLoader的私有构造函数中可以看出,在选择ExtensionFactory的时候,并不是调用getExtension(name)来获取某个具体的实现类,而是调用getAdaptiveExtension来获取一个自适应的实现。那么首先我们就来分析一下getAdaptiveExtension这个方法的实现吧:

切入getAdaptiveExtension方法

在这里插入图片描述
这里先从cachedAdaptiveInstance缓存中获取自适应实例,为空则去创建一个,这里使用了双重检查机制!那么这里创建自适应实例的方法就是createAdaptiveExtension()!

切入createAdaptiveExtension()方法
在这里插入图片描述
在createAdaptiveExtension方法中,首先通过getAdaptiveExtensionClass方法获取到最终的自适应实现类型,然后实例化一个自适应扩展实现的实例,最后进行扩展点注入操作。

 return injectExtension((T) getAdaptiveExtensionClass().newInstance());

这行代码我们拆成三部分来分析,第一部分是getAdaptiveExtensionClass方法,第二部分就是创建实例newInstance,然后执行injectExtension方法!接着分析

进入getAdaptiveExtensionClass
在这里插入图片描述
他只是简单的调用了getExtensionClasses方法,然后在判adaptiveCalss缓存是否被设置,如果被设置那么直接返回,否则调用createAdaptiveExntesionClass方法动态生成一个自适应实现
进入getExtensionClasses()方法
在这里插入图片描述
这里又是一个双重检查!cachedClasses为空是执行loadExtensionClasses()方法!加载完成之后就会进行缓存。也就是说对于每个扩展点,其实现的加载只会执行一次。
切入loadExtensionClasses()
在这里插入图片描述
注意这里的type是ExtensionFactory,这里为什么是ExtensionFactory等下在分析!问题!
首先会检测扩展点在@SPI注解中配置的默认扩展实现的名称,并将其赋值给cachedDefaultName属性进行缓存,后面想要获取该扩展点的默认实现名称就可以直接通过访问cachedDefaultName字段来完成,比如getDefaultExtensionName方法就是这么实现的。从这里的代码中又可以看到,具体的扩展实现类型,是通过调用loadFile方法来加载,分别从一下三个地方加载:

  • META-INF/dubbo/internal/
  • META-INF/dubbo/
  • META-INF/services/

切入loadDirectory方法
在这里插入图片描述

这个方法就是得到加载文件读取路径的
进入loadResource方法在这里插入图片描述
这里有调用了loadClass方法,这个方法是加载扩展实现类
在这里插入图片描述
切入loadClass方法
在这里插入图片描述
在这里插入图片描述
首先是类型检查一下,然后有三种加载方式!有点长,我们拆分来看!
判断该实现类是否@Adaptive,是的话不会放入extensionClasses/cachedClasses缓存
判断是否Wrapper类型,是的话放入到Wrapper实现类缓存中
不是Wrapper类型,普通实现类型,则放入cachedActivates缓存

  • cachedAdaptiveClass : 当前Extension类型对应的AdaptiveExtension类型(只能一个)
  • cachedWrapperClasses : 当前Extension类型对应的所有Wrapper实现类型(无顺序)
  • cachedActivates : 当前Extension实现自动激活实现缓存(map,无序)
  • cachedNames : 扩展点实现类对应的名称(如配置多个名称则值为第一个)

其实也就是说,在调用了getExtensionClasses方法之后,当前扩展点对应的实现类的一些信息就已经加载进来了并且被缓存了。后面的许多操作都可以直接通过这些缓存数据来进行处理了。

那么这里在loadResource方法中的while循环将实现类加载,那么while执行完后loadExtensionClasses()方法

回到loadExtensionClasses方法
在这里插入图片描述
将扩展点实现Map返回!继续返回getExtensionClasses()方法!

返回getExtensionClasses()方法
在这里插入图片描述
将加载好的扩展点放入到cachedClasses缓存中!继续向上放回
回到getAdaptiveExtensionClass()方法
在这里插入图片描述
通过getExtensionClasses();方法执行后,在loadClass的时候已经将cachedAdaptiveClass赋值
了如下!
在这里插入图片描述
所以这里cachedAdaptiveClass是有值的,那么直接返回cachedAdaptiveClass,向上返回!
返回到createAdaptiveExtension()方法
在这里插入图片描述
这里其实就是上面标注了 接着分析 的那个地方的代码,这里getAdaptiveExtensionClass()得到的是AdaptiveExtensionFactory对象,那么.newInstance()执行的就是下面这块代码
在这里插入图片描述

ExtensionLoader.getExtensionLoader(ExtensionFactory.class)

执行getExtensionLoader方法,type为ExtensionFactory其实已经有值了,就可以直接从缓存中获取!

for (String name : loader.getSupportedExtensions()) {

loader.getSupportedExtensions()方法
在这里插入图片描述
这个getExtensionClasses方法是从cachedClasses中获取值,getExtensionClasses方法在getAdaptiveExtensionClass方法中调用服,也是将cachedClasses赋值了的,所以也是从缓存中取值即可!这里取到之后回到for中
在这里插入图片描述
getExtension()这个方法,这条主线先不分析,放在下面分析获取扩展点的时候在分析也是一样的,不然这条主线分析下去会讲完!回到
在这里插入图片描述
继续往上返回getAdaptiveExtension方法!
在这里插入图片描述
回到梦想开始的地方ExtensionLoader
在这里插入图片描述
往上回到getExtensionLoader方法
在这里插入图片描述
此时就构建好了type为LoginService的扩展点,该扩展点信息如下
在这里插入图片描述
那么到这里获取扩展点加载器就到这里了!接下来开始分析getExtension部分源码!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员劝退师-TAO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值