Dubbo SPI 源码深入分析

Posted 董博士的大学室友

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo SPI 源码深入分析相关的知识,希望对你有一定的参考价值。

1.先看入口在哪里,我们加载自定义的扩展都会写这行代码,那么就从分析ExtensionLoader开始了

 

 

ExtensionLoader.getExtensionLoader(XXX.class).getExtension("diyExtension");

1.1 getExtensionLoader
 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是否创建过了,创建过的会放在chm里面
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
        //没创建过就创建,放到chm里面 EXTENSION_LOADERS.putIfAbsent(type,
new ExtensionLoader<T>(type)); loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); } return loader; }

 

1.1.1 new ExtensionLoader 的时候,先判断你是不是在要ExtensionFactory的扩展点,如果不是的话,就去拿ExtensionFactory的自适应扩展点(这里有待进一步研究为何这个逻辑)然后赋值给objectFactory (ExtensionLoader(protocol) 的成员变量:private final ExtensionFactory objectFactory;)

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

 

1.1.2

此时回到上层方法,我们走完了new ExtensionLoader得到了一个ExtensionLoader,这个ExtensionLoader里面,带着成员变量ExtensionFactory,其值是经过自适应处理的ExtensionFactory,然后把 这个ExtensionLoader放到了chm里面(为什么呢?比如我在1.1处ExtensionLoader.getExtensionLoader(XXX.class)的XXX处入参传的是Protocol入参,但是你给我的是ExtensionFactory 相关的扩展点,是不是我要个苹果 ,看起来你给了我香蕉?)

 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);
        }

1.2 此时执行1.1处的 getExtension,这里,是根据传的我们自定义的名字,去一个chm找是否有,没有创建一个,放到chm里,再查出来把他返回

 public T getExtension(String name) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        Holder<Object> holder = getOrCreateHolder(name);
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

private Holder<Object> getOrCreateHolder(String name) {
  
  //ExtensionLoader的成员变量 private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
    Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<>());
holder = cachedInstances.get(name);
}
return holder;
}
 
public class Holder<T> {

private volatile T value;

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

public T get() {
return value;
}

}
 

以上是关于Dubbo SPI 源码深入分析的主要内容,如果未能解决你的问题,请参考以下文章

深入了解JDK SPI的源码分析及实践使用方式,看完对你应该有所帮助

Dubbo底层源码分析之SPI扩展点

dubbo源码分析01:SPI机制

源码分析---SOFARPC可扩展的机制SPI

Dubbo SPI源码分析

Dubbo 2.7.3源码分析——JDK SPI篇