dubbo源码一:ExtensionLoader及获取适配类过程解析

一、核心代码

ExtensionLoader第一次加载过程,以Protocol接口为为例,入口是:

public static void main(String[] args) {
   Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
}

二、获取Protocol的ExtensionLoader

直接进入ExtensionLoader类中
Debug-1:
在这里插入图片描述
这里会创建ExtensionLoader,看一下创建过程:
Debug-2:
在这里插入图片描述
由于type是Protocol接口,不等于ExtensionFactory.class,所以走ExtensionLoader.getExtensionLoader(ExtensionFactory.class),然后接着走回了getExtensionLoader函数,不过这次type是ExtensionFactory类型,如下:
Debug-3:
在这里插入图片描述
接着会创建ExtensionLoader,再看一下创建过程:
Debug-4:
在这里插入图片描述
此时type是ExtensionFactory接口,等于ExtensionFactory.class,所以ObjectFactory=null。这样就完成了ExtensionFactory类型的ExtensionLoader的创建,回到Debug-3处,走完Debug-3后,变量EXTENSION_LOADERS已经包含了<ExtensionFactory, ExtensionLoader>,即如下:
Debug-5:
在这里插入图片描述
接着Debug-2往下走,即会执行getAdaptiveExtension方法(获取适配类),如下:
Debug-6:
在这里插入图片描述
Debug-7:
在这里插入图片描述
Debug-8:
在这里插入图片描述
Debug-9:
在这里插入图片描述
cachedClasses用于存放加载配置文件的类,此时内容为null,因为沿未加载配置文件

private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String,Class<?>>>();

在这里插入图片描述
接着debug:
Debug-10:
在这里插入图片描述
上面的type类型是interface com.alibaba.dubbo.common.extension.ExtensionFactory ,但由于ExtensionFactory只有@SPI注解,value属性不存在值,所以程序走下去,从以下三个路径和类名(即指定目录前缀+类全名)组成的路径加载资源文件:

SERVICES_DIRECTORY = "META-INF/services/"
DUBBO_DIRECTORY = "META-INF/dubbo/"
DUBBO_INTERNAL_DIRECTORY = "META-INF/dubbo/internal/"

loadFile函数的主要作用是加载资源文件,并缓存其内容。核心函数如下:
在这里插入图片描述
Debug-10 执行完毕后,返回的map中的内容有:<“Spring”, SpringExtensionFactory>、<“Spi”, SpiExtensionFactory>
在这里插入图片描述
同时,Debug-9返回,接着执行Debug-8,此时 AdaptiveExtensionFactory 已经缓存在 cachedAdaptiveClass 中,所以直接返回,见下:
在这里插入图片描述
接着回到Debug-7,创建 AdaptiveExtensionFactory 实例,即如下:
在这里插入图片描述
创建 AdaptiveExtensionFactory 实例时,首先获取 ExtensionLoader,此前已经初始化ok。然后依次实例化具体实现(放在ExtensionLoader类cachedClasses属性中,这个属性用于存放实现功能接口的类,即上面解析得到的extensionClasses),即依次实例化SpiExtensionFactory和SpringExtensionFactory,事实上AdaptiveExtensionFactory是通用扩展实现获取的入口,具体的获取方式分为两种,一种是通过Dubbo自己的SPI方式加载到的扩展,另一种是支持复用Spring的方式。以key为“spi”,value是 SpiExtensionFactory 为例,如下:
Debug-11:
在这里插入图片描述
在这里插入图片描述
上述 injectExtension 方法对封装类的成员变量进行初始化工作,其过程是:
(1)获取公有的set方法,解析出成员变量的名称。
(2)调用ExtensionFactory.getExtension方法获取成员变量的值。这里不同的ExtensionFactory实现会调用不同的实现。
(3)通过反射的方式调用set方法完成成员变量值的注入。
至此,SpiExtensionFactory 实例化完成,同理 SpringExtensionFactory类实例化原理是一样的。当所有的扩展点实现类的实例对象创建完毕,AdaptiveExtensionFactory类中的 factories 属性值如下,可以看出,这两个扩展点实现类只是实例化了,由于其内部没有set方法,故没有字段。
在这里插入图片描述

接着再次进入Debug-7,调用 injectExtension 方法对 AdaptiveExtensionFactory 类的成员变量进行初始化工作。
接着再次进入Debug-6,实例化 AdaptiveExtensionFactory 完成,同时把实例化后的对象放到 ExtensionLoader 类 cachedAdaptiveInstance 属性。
接着再次进入Debug-2,此时的 objectFactory 的值是AdaptiveExtensionFactory 的实例化对象,该实例化对象的factories属性含有两个扩展点实现类的实例化对象,即:
在这里插入图片描述
接着再次进入Debug-1,得到type是Protocol的ExtensionLoader,即
在这里插入图片描述
在这里插入图片描述

三、获取Protocol的AdaptiveExtension

上面获取了Protocol接口的ExtensionLoader,从上面结果上看,结果ExtensionLoader中的cachedAdaptiveInstance为null,所以直接进入源码:
Debug-1:
在这里插入图片描述
Debug-2:
在这里插入图片描述
Debug-3:
在这里插入图片描述
Debug-4:
在这里插入图片描述
Debug-5:
在这里插入图片描述
由于Protocol接口上@SPI("dubbo”),即指定了默认实现,同时把解析结果放到了cachedDefaultName属性中,然后从资源文件中加载其他Protocol实现,路径示例如下:

META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol文件中有:
filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=org.apache.dubbo.rpc.support.MockProtocol

dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol

另外两个文件路径如下:

    META-INF/services/org.apache.dubbo.rpc.Protocol
    META-INF/dubbo/org.apache.dubbo.rpc.Protocol

加载核心过程如下,加载的类都存放在cachedWrapperClasses Set集合中:
在这里插入图片描述
加载完所有的资源文件后,Debug-5中就会走完,此时extensionClasses内容如下:
在这里插入图片描述
可以看出,所有Protocol的扩展类实现者都放到了 extensionClasses 中,也同时把符合的wrapper(即有type类型的构造函数的wrapper:clazz.getConstructor(type))缓存到了 cachedWrapperClasses Set 集合中。
在这里插入图片描述
接着再次进入Debug-4,并把 extensionClasses 中的map集合缓存到了 cachedClasses 中,并返回。
在这里插入图片描述
接着再次进入Debug-3,由于Protocol获取到的ExtensionLoader中的cachedAdaptiveClass为null(见上面ExtensionLoader中的变量值),所以在Debug-6中会创建Protocol的适配扩展类,如下:
Debug-6:
在这里插入图片描述
Debug-7:
在这里插入图片描述
自适应实现只能有一个,自适应实现类获取有两种方式:

  1. 一种是通过配置文件,这种就是针对@Adaptive注解在类级别的时,如AdaptiveExtensionFactory。
  2. 另外一种是@Adaptive注解在方法级别时,自适应实现类就需要通过字符码动态生成,如Protocol的export和refer方法。

介绍完上面,程序接着走完Debug-6,cachedAdaptiveClass会缓存Protocol的适配类,走回到Debug-2调用injectExtension方法对Protocol适配类成员变量进行初始化工作。
接着再次进入Debug-1,获取Protocol的适配类实例,并缓存到cachedAdaptiveInstance中去,另外,整个获取Protocol实例完成,其中ExtensionLoader变量值内容如下:
Debug-8:
在这里插入图片描述
在这里插入图片描述
其中:

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

附上Protocol的适配类的源码:

package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
    
    public void destroy() {
        throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }
    
    public int getDefaultPort() {
        throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }
    
    public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
        if (arg1 == null) 
            throw new IllegalArgumentException("url == null”);

        com.alibaba.dubbo.common.URL url = arg1;
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );

        if(extName == null) 
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol]));

        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
    
    public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {

        if (arg0 == null) 
            throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null”);

        if (arg0.getUrl() == null) 
            throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null”);

        com.alibaba.dubbo.common.URL url = arg0.getUrl();
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );

        if(extName == null) 
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol]));

        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }
}

我的修行之路,欢迎讨论!
微信:bboyzqh
邮箱:1003505819@qq.com

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bboyzqh

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

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

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

打赏作者

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

抵扣说明:

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

余额充值