dubbo-SPI扩展点加载机制简解

2018-03-08  本文已影响0人  南宋临安府

“天长地久。
天地所以能长且久者,以其不自生,故能长生。
是以圣人后其身而身先,外其身而身存。
非以其无私耶?
故能成其私。”[1]

jdk-SPI (Service Provider Interface)

SPI (Service Provider Interface),一种服务发现机制,为某个接口寻找服务实现的机制。dubbo-SPI就是基于此并有所加强。
在dubbo的源码中,像如下代码段会随处可见:

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

这便是duboo-SPI的使用方式。

dubbo-SPI

特性:

代码结构如下:

com.alibaba.dubbo.common.extension  
 |  
 |--factory  
 |     |--AdaptiveExtensionFactory     
 |     |--SpiExtensionFactory    
 |     |--SpringExtensionFactory      
 |  
 |--support  
 |     |--ActivateComparator  
 |  
 |--Activate  #自动激活加载扩展的注解  
 |--Adaptive  #自适应扩展点的注解  
 |--ExtensionFactory  #扩展点对象生成工厂接口  
 |--ExtensionLoader   #扩展点加载器,扩展点的查找,校验,加载等核心逻辑的实现类  
 |--SPI   #扩展点注解

需要我们最为关心的就是ExtensionLoader,几乎所有特性都在这个类中实现。
ExtensionLoader没有提供public的构造方法,但是提供了一个public static的getExtensionLoader,这个方法就是获取ExtensionLoader实例的工厂方法。其public成员方法中有三个比较重要的方法:

ExtensionLoader

想要获取某个扩展的实现,首先要获取到该扩展对应的ExtensionLoader实例。

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 interface!");
        }
        if (!withExtensionAnnotation(type)) { //注解判断
            throw new IllegalArgumentException("Extension type(" + type +
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }
        //从静态缓存中获取
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            //为Extension类型创建ExtensionLoader实例
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
}

上述方法需要一个Class类型的参数,该参数表示希望加载的扩展点类型,该参数必须是接口,且该接口必须被@SPI注解注释,否则拒绝处理。检查通过之后首先会检查ExtensionLoader缓存中是否已经存在该扩展对应的ExtensionLoader,如果有则直接返回,否则创建一个新的ExtensionLoader负责加载该扩展实现,同时将其缓存起来。所以对于每一个扩展,dubbo中只会有一个对应的ExtensionLoader实例。

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

从ExtensionLoader的构造函数中可以看到,如果要加载的扩展点类型是ExtensionFactory是,objectFactory字段被设置为null。由于ExtensionLoader的使用范围有限(基本上局限在ExtensionLoader中),因此对他做了特殊对待:在需要使用ExtensionFactory的地方,都是通过对应的自适应实现来代替。
objectFactory属性是一个ExtensionFactory类型,ExtensionFactory主要用于加载扩展的实现:

public interface ExtensionFactory {

    /**
     * Get extension.
     *
     * @param type object type.
     * @param name object name.
     * @return object instance.
     */
    <T> T getExtension(Class<T> type, String name);

}

ExtensionFactory被@SPI注解注释,说明他也是一个扩展点,dubbo内部提供了三个实现类:SpiExtensionFactory 、AdaptiveExtensionFactory以及SpringExtensionFactory,不同的实现可以已不同的方式来完成扩展点实现的加载。
默认的ExtensionFactory实现中,AdaptiveExtensionFactotry被@Adaptive注解,它就是ExtensionFactory对应的自适应扩展实现(每个扩展点最多只能有一个自适应实现,如果所有实现中没有被@Adaptive注释的,那么dubbo会动态生成一个自适应实现类),也就是说,所有对ExtensionFactory调用的地方,实际上调用的都是AdpativeExtensionFactory,那么我们看下他的实现代码:

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        // 将所有ExtensionFactory实现保存起来  
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    public <T> T getExtension(Class<T> type, String name) {
        // 依次遍历各个ExtensionFactory实现的getExtension方法,一旦获取到Extension即返回  
        // 如果遍历完所有的ExtensionFactory实现均无法找到Extension,则返回null
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

他会遍历当前系统中所有的ExtensionFactory实现来获取指定的扩展实现,获取到扩展实现或遍历完所有的ExtensionFactory实现。这里调用了ExtensionLoader的getSupportedExtensions方法来获取ExtensionFactory的所有实现,又回到了ExtensionLoader类。

方法代码分析

getExtension(name)  
    -> createExtension(name) #如果无缓存则创建  
        -> getExtensionClasses().get(name) #获取name对应的扩展类型  
        -> 实例化扩展类  
        -> injectExtension(instance) # 扩展点注入  
        -> instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)) #循环遍历所有wrapper实现,实例化wrapper并进行扩展点注入
public T getAdaptiveExtension()  
    -> createAdaptiveExtension() #如果无缓存则创建  
        -> getAdaptiveExtensionClass().newInstance() #获取AdaptiveExtensionClass  
            -> getExtensionClasses() # 加载当前扩展所有实现,看是否有实现被标注为@Adaptive  
            -> createAdaptiveExtensionClass() #如果没有实现被标注为@Adaptive,则动态创建一个Adaptive实现类  
                -> createAdaptiveExtensionClassCode() #动态生成实现类java代码  
                -> compiler.compile(code, classLoader) #动态编译java代码,加载类并实例化  
        -> injectExtension(instance)  

能在本地把代码跑起来,debug状态能更好的跟踪代码的执行,dubbo源代码中提供了非常详细的测试用例,基本涵盖了所有的使用场景,可以本地试试,大有裨益!

com.alibaba.dubbo.common.extensionloader.ExtensionLoaderTest

  1. 老子《道德经》第七章,老子故里,中国鹿邑。

上一篇 下一篇

猜你喜欢

热点阅读