ExtensionLoader详解

ExtensionLoader 注入的依赖扩展点是一个 Adaptive 实例,直到扩展点方法执行时才决定调用是哪一个扩展点实现。

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

Dubbo 改进了 JDK 标准的 SPI 的以下问题:

  1. JDK标准的SPI是一次性实例化所有的扩展点实现,比较消耗资源,而dubbo是在方法执行时才决定调用哪个扩展点
  2. JDK 如果扩展点加载失败,连扩展点的名称都拿不到了
  3. 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。

dubbo默认约定文件放在META-INF/dubbo/internal下。

扩展点加载

ExtensionLoader#getExtensionLoader(Class type)

    @SuppressWarnings("unchecked")
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("Extension type == null");
        }
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
        }
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        }

        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

加载扩展点,主要分为三步:

  1. 校验类型是否为接口
  2. withExtensionAnnotation校验是否包含SPI注解
  3. EXTENSION_LOADERS 缓存获取扩展点,如果不存在则生成对应的扩展点并放入缓存

初始化 ExtensionLoader

    private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

初始化 ExtensionFactory ExtensionLoader

ExtensionLoader.getExtensionLoader(ExtensionFactory.class) 一次回调获取到对应的ExtensionFactory的扩展点。
但是在回调时,我们看到以上的构造函数返回了null。

type == ExtensionFactory.class ? null

所以ExtensionFactory的扩展点是在ExtensionLoader#getDefaultExtension 初始化。

  /**
     * synchronized in getExtensionClasses
     */
    private Map<String, Class<?>> loadExtensionClasses() {
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();

        for (LoadingStrategy strategy : strategies) {
            loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
            loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
        }

        return extensionClasses;
    }

ExtensionFactory 类图

在这里插入图片描述

ExtensionLoader#getExtension()

    public T getExtension(String name) {
        return getExtension(name, true);
    }
    public T getExtension(String name, boolean wrap) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        final Holder<Object> holder = getOrCreateHolder(name);
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = createExtension(name, wrap);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
  1. 校验数据是否正常
  2. 创建Holder 对象
  3. 创建createExtension

Holder

/**
 * Helper Class for hold a value.
 */
public class Holder<T> {

    private volatile T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }

}

createExtension

 T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            injectExtension(instance);

总结

整个ExtensionFactory的加载扩展其实宏观分为以下几个步骤:
1、LoadFile加载ExtensionFactory对应的SPI文件及内容。
2、ExtensionFactory对应的AdaptiveExtensionFactory的对象实例化。
3、AdaptiveExtensionFactory构造函数内部初始化SpringExtensionFactory和SpiExtensionFactory。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值