Dubbo SPI

META-INF/dubbo下的文件可以使用#注释

ExtensionLoader

  • 基本字段说明

以下字段可以分为class字段(如cacheNames)与实例字段(如cacheInstances)

public class ExtensionLoader {
    //对不同的接口记录对应的ExtensionLoader
    private static final ConcurrentMap, ExtensionLoader> EXTENSION_LOADERS = new ConcurrentHashMap<>();
    //对不同的class记录产生的实例,共享所有接口对应的实现实例
    private static final ConcurrentMap, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();
    //loader对应的接口
    private final Class type;
    //对接口ExtensionFactory是null,其余接口是AdaptiveExtensionFactory实例
    private final ExtensionFactory objectFactory;
    //记录当前接口对应的实现class及className
    private final ConcurrentMap, String> cachedNames = new ConcurrentHashMap<>();
    //Holder内部是volatile,记录className及对应的class
    private final Holder>> cachedClasses = new Holder<>();
    private final Map cachedActivates = new ConcurrentHashMap<>();
    //记录当前接口对应的className及实现实例Holder
    private final ConcurrentMap> cachedInstances = new ConcurrentHashMap<>();
    //适配实例,loader不指定实现名称时使用适配实例
    private final Holder cachedAdaptiveInstance = new Holder<>();
    //适配class
    private volatile Class cachedAdaptiveClass = null;
    //接口中@SPI声明的名称
    private String cachedDefaultName;
    private volatile Throwable createAdaptiveInstanceError;
    //实现外层包裹的多层装饰类
    private Set> cachedWrapperClasses;
    private Map exceptions = new ConcurrentHashMap<>();
}
 
 

核心逻辑研究

  • 使用原则
//获取META-INF配置文件中包含哪些实现
extensionLoader.getExtensionClass()
//当上下文逻辑中指定实现名称时使用
extensionLoader.getExtension(name);
//当上下文逻辑中没有指定名称时使用
extensionLoader.getAdaptiveExtension()
  • 测试入口
//测试代码
public void testDubboSpi() {
  //初始化ExtensionLoader实例(class字段及实例字段)
  //初始化ExtensionLoader实例,仅设置type和objectFactory字段,不会初始化class相关字段
  ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
  // 内部调用extensionLoader.getExtensionClass初始化class相关字段,获取包裹了wrapper的实例
  Robot bumblebee = extensionLoader.getExtension("bumblebee");
  bumblebee.sayHello();
  // 测试自动注入Battery字段
  Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
  optimusPrime.sayHello();
  // 获取自动注入
  Robot compoundRobot = extensionLoader.getExtension("compound");
  compoundRobot.sayHello();
}
  • ExtensionLoader.getExtensionLoader(Robot.class)
//函数调用链
ExtensionLoader.getExtensionLoader(Robot.class)
ExtensionLoader.getExtensionLoader(ExtensionFactory.class))
//未指定实现,获取adaptive实现
ExtensionLoader.getAdaptiveExtension()
//获取AdaptiveExtensionClass并初始化adaptive实例
getAdaptiveExtensionClass().newInstance()
//获取META-INF中对应的名称与实现的对应关系
getExtensionClasses()
//扫描META-INF/dubbo等默认配置路径
loadExtensionClasses()
//根据配置文件中名称与实现初始化loader中class字段
loadClass()
//newInstance()时调用默认构造函数,初始化loader中实例字段并设置SpiFactory和SpringFactory
AdaptiveExtensionFactory()
//将AdaptiveExtensionFactory设置到ExtensionLoader中

private ExtensionLoader(Class type) {
    this.type = type;
    //第一次调用ExtensionLoader.getExtensionLoader(type)时初始化ExtensionLoader实例
    //初始化实例时仅设置type和objectFactory字段
    //type!=ExtensionFactory时objectFactory为AdaptiveExtensionFactory实例
    objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

private T createAdaptiveExtension() {
    //newInstance()时会调用默认构造函数,如AdaptiveExtensionFactory()
    //这里调用injectExtension方法的目的是为手工编码的自适应拓展注入依赖
    return injectExtension((T) getAdaptiveExtensionClass().newInstance());
}

private Class getAdaptiveExtensionClass() {
    getExtensionClasses();
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

private Map> loadExtensionClasses() {
    //根据@SPI("")设置defaultName
    cacheDefaultExtensionName();
    Map> extensionClasses = new HashMap<>();
    //在以下目录寻找SPI配置并初始化本ExtensionLoader中的相关字段
    loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
    loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
    loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
    loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
    loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
    loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
    return extensionClasses;
}

//处理spi配置中每一行记录
//设置AdaptiveClass,WrapperClass,class->className,className->class字段
private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class clazz, String name) throws NoSuchMethodException {
    if (clazz.isAnnotationPresent(Adaptive.class)) {
        //设置cachedAdaptiveClass字段,多于一个AdaptiveClass抛出异常
        cacheAdaptiveClass(clazz);
    //通过clazz.getConstructor(type)是否报异常来判断
    } else if (isWrapperClass(clazz)) {
        //设置cachedWrapperClasses字段
        cacheWrapperClass(clazz);
    } else {
        // 检测 clazz 是否有默认的构造方法,如果没有,则抛出异常
        clazz.getConstructor();
        String[] names = NAME_SEPARATOR.split(name);
        //判断并设置cachedActivates字段
        cacheActivateClass(clazz, names[0]);
        for (String n : names) {
            //设置cachedNames
            cacheName(clazz, n);
            //返回后设置cachedClasses
            saveInExtensionClass(extensionClasses, clazz, name);
        }
    }
}

public AdaptiveExtensionFactory() {
    ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
    List list = new ArrayList();
    //初始化SpiExtensionFactory和SpringExtensionFactory实例,设置cachedInstances字段和EXTENSION_INSTANCES字段
    for (String name : loader.getSupportedExtensions()) {
        list.add(loader.getExtension(name));
    }
    factories = Collections.unmodifiableList(list);
}
  • extensionLoader.getExtension("bumblebee")
//META-INF中配置
bumblebee = com.my.study.business.impl.dubbo.pojo.BumblebeeRobot
wrapper = com.my.study.business.impl.dubbo.pojo.RobotWrapper

//初始化实例
//Ioc注入,Wrapper处理
private T createExtension(String name) {
    //初始化当前loader涉及的实现class(不初始化实例)
    Class clazz = getExtensionClasses().get(name);
    T instance = (T) EXTENSION_INSTANCES.get(clazz);
    if (instance == null) {
        // 初始化新实例,调用默认构造函数
        EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
        instance = (T) EXTENSION_INSTANCES.get(clazz);
    }
    // Ioc注入其他实现字段
    injectExtension(instance);
    Set> wrapperClasses = cachedWrapperClasses;
    if (CollectionUtils.isNotEmpty(wrapperClasses)) {
        for (Class wrapperClass : wrapperClasses) {
            //支持多个wrapper,多重代理,实现的不错
            instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
        }
    }
    return instance;
}
  • extensionLoader.getExtension("optimusPrime")
//函数调用链
//extensionLoader.getExtension时扫描
getExtension(robot).injectExtension(instance)
adaptiveExtensionFactory.getExtension()
//若type声明了@Spi,则走spiExtensionFactory,否则走springExtensionFactory,如何初始化SpringExtensionFactory呢?
spiExtensionFactory.getExtension()
//未指定battery实现,获取AdaptiveExtension
extensionLoader.getAdaptiveExtension()
//获取AdaptiveExtensionClass:首先判断META-INF配置文件中是否指定AdaptiveExtensionClass,如果未指定则临时创建代理类
extensionLoader.getAdaptiveExtensionClass()
//创建代理类
Class c=createAdaptiveExtensionClass()
//创建代理类实例并在上文injectExtension(instance)中通过setter方法注入

private T injectExtension(T instance) {
if (objectFactory != null) {
 for (Method method : instance.getClass().getMethods()) {
   //找到setter方法
   if (isSetter(method)) {
     String property = getSetterProperty(method);
     //adaptiveExtensionFactory调用,property其实无用
     Object object = objectFactory.getExtension(pt, property);
     if (object != null) {
       //set回去
       method.invoke(instance, object);
                    
private Class getAdaptiveExtensionClass() {
    getExtensionClasses();
    if (cachedAdaptiveClass != null) {
        //如果META-INF中配置了AdaptiveExtensionClass则直接使用(如AdaptiveExtensionFactory.class)
        return cachedAdaptiveClass;
    }
    //如未配置,则需要临时创建
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

private Class createAdaptiveExtensionClass() {
    //创建代理类java code,code中每个函数根据入参Url及type函数@Adaptive注解指定的名称选择并调用实现中对应的函数。
    //接口中某method未声明@Adaptive时,代理类中该method body为throw UnsupportOperationException()
    //为什么该代理类要临时创建?因为需要继承对应的接口并实现相应的方法,无法使用通用的逻辑,创建并完成Ioc注入后后续调用可以直接使用。
    String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
    ClassLoader classLoader = findClassLoader();
    //选择创建代理类的库,使用META-INF文件中指定的AdaptiveCompiler
    org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
    return compiler.compile(code, classLoader);
}

//AdaptiveCompiler
public Class compile(String code, ClassLoader classLoader) {
    Compiler compiler;
    ExtensionLoader loader = ExtensionLoader.getExtensionLoader(Compiler.class);
    String name = DEFAULT_COMPILER; 
    // 使用设置的compile
    if (name != null && name.length() > 0) {
        compiler = loader.getExtension(name);
    } else {
        //使用默认的compiler,默认是JavassistByte
        compiler = loader.getDefaultExtension();
    }
    return compiler.compile(code, classLoader);
}

//JavassitByte生成的代码
package com.my.study.business.impl.dubbo.pojo.battery;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Battery$Adaptive implements com.my.study.business.impl.dubbo.pojo.battery.Battery {

public void uninstall(org.apache.dubbo.common.URL arg0)  {
//未声明@Activate的method直接写入异常抛出
throw new UnsupportedOperationException("The method public abstract void com.my.study.business.impl.dubbo.pojo.battery.Battery.uninstall(org.apache.dubbo.common.URL) of interface com.my.study.business.impl.dubbo.pojo.battery.Battery is not adaptive method!");
}

public void install(org.apache.dubbo.common.URL arg0)  {
   if (arg0 == null) throw new IllegalArgumentException("url == null");
   org.apache.dubbo.common.URL url = arg0;
   //从url中获取实现的名称
   String extName = url.getParameter("id", url.getParameter("type"));
   if(extName == null) throw new IllegalStateException("Failed to get extension (com.my.study.business.impl.dubbo.pojo.battery.Battery) name from url (" + url.toString() + ") use keys([id, type])");
   com.my.study.business.impl.dubbo.pojo.battery.Battery extension = (com.my.study.business.impl.dubbo.pojo.battery.Battery)ExtensionLoader.getExtensionLoader(com.my.study.business.impl.dubbo.pojo.battery.Battery.class).getExtension(extName);
   extension.install(arg0);
}
}
  • batteryExtensionLoader.getActivateExtension(URL.valueOf("?type=water"), new String[] {"nuclear"}, null)

与Ioc无关,直接调用getActivateExtension()才会获取满足@Activate条件的Extension

public List getActivateExtension(URL url, String[] values, String group) {
//获取META-INF配置中未被new String[] {"nuclear"}指定且入参group、url与@Activate.group和value值不违背的extension
if (isMatchGroup(group, activateGroup)) {
    T ext = getExtension(name);
    if (!names.contains(name)
            && !names.contains(REMOVE_VALUE_PREFIX + name)
            && isActive(activateValue, url)) {
        exts.add(ext);
    }
}
//获取META-INF配置中由new String[] {"nuclear"}指定的extension
for (int i = 0; i < names.size(); i++) {
    String name = names.get(i);
    if (!name.startsWith(REMOVE_VALUE_PREFIX)
            && !names.contains(REMOVE_VALUE_PREFIX + name)) {
        T ext = getExtension(name);
        usrs.add(ext);

    }
}
//组合以上结果
exts.addAll(usrs);

DubboSpiIoc vs SpringIoc

DubboSpi与SpringIoc二者都是从配置依赖注入策略。

  • SpringIoc

Spring可以通过@Component注入策略,可以使用@Qualifier引用注入,可以选择lazyInit延迟初始化,可以使用applicationContext.getBean(name,class)根据函数参数使用对应的实现

  • DubboSpiIoc

在meta中配置策略,通过ExtensionLoader手动获取指定的策略,支持Ioc扫描注入临时产生的代理类以实现参数动态策略选择。

DubboSpi包含的功能SpringIoc都有,为啥还要使用DubboSpi?是为了保持轻量和解耦Spring吗?

你可能感兴趣的:(Dubbo SPI)