Dubbo Spi机制

本质:将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。

java SPI:用来设计给服务提供商做插件使用的。基于策略模式来实现动态加载的机制。我们在程序只定义一个接口,具体的实现交个不同的服务提供者;在程序启动的时候,读取配置文件,由配置确定要调用哪一个实现。具体流程为:

  1. 需要在 classpath 下创建一个目录,该目录命名必须是:META-INF/service。
  2. 在该目录下创建一个 文本文件,该文件需要满足以下几个条件:文件名必须是扩展的接口的全路径名称、文件内部描述的是该扩展接口的所有实现类、文件的编码格式是 UTF-8。
  3. 通过 java.util.ServiceLoader 的加载机制来加载服务。

javaSPI我们最熟悉的应用就是数据库驱动了,mysql和oracle驱动针对JDBC分别有自己的实现,这就有赖于java的SPI机制。

JDK SPI 机制就存在以下一些问题:

  1. 实现类会被全部遍历并且实例化,假如我们只需要使用其中的一个实现,这在实现类很多的情况下无疑是对机器资源巨大的浪费。
  2. 无法按需获取实现类,不够灵活,我们需要遍历一遍所有实现类才能找到指定实现。

Dubbo SPI:在dubbo中也有SPI机制,虽然都需要将接口全限定名配置在文件中,但是dubbo并没有使用java的spi机制,而是重新实现了一套功能更强【支持AOP与依赖注入】的 SPI 机制,并且 利用缓存提高加载实现类的性能,同时支持实现类的灵活获取。基于SPI,我们可以很容易的对 Dubbo 进行拓展。例如dubbo当中的protocol,LoadBalance等都是通过SPI机制扩展。具体实现流程如下:

  1. 需要在 classpath 下创建一个目录,该目录命名可以是:META-INF/service/、META-INF/dubbo/、META-INF/dubbo/internal/。
  2. 在该目录下创建一个 文本文件,该文件需要满足以下几个条件:文件名必须是扩展的接口的全路径名称、文件内部描述的是该扩展接口的所有实现类,将服务实现类写成KV键值对的形式,Key是拓展类的name,Value是扩展的全限定名实现类。
  3. 通过 org.apache.dubbo.common.extension.ExtensionLoader 的加载机制来加载服务。

java SPI和dubbo SPI对比:

  1. Java SPI在加载扩展点的时候,会一次性加载所有可用的扩展点,很多是不需要的,会浪费系统资源。dubboSPI有选择性地加载所需要的SPI接口。
  2. javaSPI配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。而dubboSPI配置文件中以键值对的形式有别名,易于区分。
  3. SPI扩展如果依赖其他的扩展,javaspi做不到自动注入和装配,dubbo可以实现自动注入。
  4. javaSPI不提供类似于Spring的IOC和AOP功能,dubboSPI是支持的。

Spring SPI机制之SpringFactoriesLoader约定如下:

  • 配置文件必须在META-INF/目录下,文件名必须为spring.factories。
  • 文件内容为键值对,一个键可以有多个值(逗号分割)。键和值都需要是类的全限定名,键和值可以没有任何类与类之间的关系,当然也可以有实现的关系。
// 这种方式对应的接口Driver以及配置的类可以不存在任何关系
List<String> stringList = SpringFactoriesLoader.loadFactoryNames(Driver.class, App.class.getClassLoader());
stringList.stream().forEach(item -> System.out.println(item));
// 这种方式配置的扩展类一定是接口Driver的实现类
List<Driver> drivers = SpringFactoriesLoader.loadFactories(Driver.class, App.class.getClassLoader());

如下所示:键值中值可以是任意包路径下的类。

net.csdn.spi.Driver=net.csdn.spi.Mysql,net.ali.Oracle

与Java SPI机制对比:

  1. 首先Spring的SPI机制对Java的SPI机制对进行了一些简化,Java的SPI每个接口都需要对应的文件,而Spring的SPI机制只需要一个spring.factories文件。
  2. Java的SPI机制文件内容必须为接口的实现类,而Spring的SPI并不要求键值对必须有什么关系,更加灵活。
  3. Spring的SPI机制提供了获取类限定名的方法loadFactoryNames,而Java的SPI机制是没有的。通过这个方法获取到类限定名之后就可以将这些类注入到Spring容器中,用Spring容器加载这些Bean,而不仅仅是通过反射。

Spring的SPI也同样没有实现获取指定某个指定实现类的功能,所以要想能够找到具体的某个实现类,还得依靠具体接口的设计。

所以不知道你有没有发现,PropertySourceLoader它其实就是一个策略接口,注释也有说,所以当你的配置文件是properties格式的时候,他可以找到解析properties格式的PropertiesPropertySourceLoader对象来解析配置文件。


1.ScopeModel

抽象这三个能力是为了实现 Dubbo 的多实例支持,FrameworkModel 是实现类似 JVM 租户级别的隔离,ApplicationModel 是为了实现一个机器上发布多个应用(如 demo-application1 和 demo-application2 一起发布),ModuleModel 是为了实现服务生命周期的独立管理(如一个 demo-application 可以由多个 Spring 容器共同提供)。

public abstract class ScopeModel implements ExtensionAccessor {

    private final ScopeModel parent;
    private final ExtensionScope scope;
    private ExtensionDirector extensionDirector;
    // 子类构造器中分别指定parent & scope
    public ScopeModel(ScopeModel parent, ExtensionScope scope, boolean isInternal) {
        this.parent = parent;
        this.scope = scope;
        this.internalScope = isInternal;
    }
    
    protected void initialize() {
        this.extensionDirector = new ExtensionDirector(parent != null ? parent.getExtensionDirector() : null, scope, this);
        this.extensionDirector.addExtensionPostProcessor(new ScopeModelAwareExtensionProcessor(this));
    }
    
    @Override
    public ExtensionDirector getExtensionDirector() {
        return extensionDirector;
    }
}

相关子类初始化时机:

  1. @EnableDubbo注解通过import方式引入类DubboConfigConfigurationRegistrar、DubboComponentScanRegistrar。
  2. 接口ImportBeanDefinitionRegistrar子类核心方法内部通过类DubboSpringInitializer触发ScopeModel相关子类。并且将Dubbo应用上下文DubboSpringInitContext、ApplicationModel、ModuleModel都被Spring IOC托管。--【@EnableDubbo该注解核心功能】
  3. FrameworkModel构造器中初始化ApplicationModel,ApplicationModel构造器中初始化ModuleModel。
  4. FrameworkModel、ApplicationModel、ModuleModel三者之间并没有Java编程语法意义上的继承关系,但是是通过父类ScopeModel的parent属性建立父子关系。
  5. FrameworkModel的parent属性为null,ApplicationModel的parent属性为FrameworkModel,ModuleModel的parent属性为ApplicationModel。

ExtensionDirector作用子类加载扩展类就是利用该类得到类ExtensionLoader完成SPI功能的。


1.1.FrameworkModel

public class FrameworkModel extends ScopeModel {
    
    public FrameworkModel() {
        super(null, ExtensionScope.FRAMEWORK, false);
        ...
        initialize();
    }

    @Override
    protected void initialize() {
        super.initialize();
        TypeDefinitionBuilder.initBuilders(this);

        serviceRepository = new FrameworkServiceRepository(this);
        // 获取 ScopeModelInitializer 类型的扩展类
        ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class);
        Set<ScopeModelInitializer> initializers = initializerExtensionLoader.getSupportedExtensionInstances();
        for (ScopeModelInitializer initializer : initializers) {
            initializer.initializeFrameworkModel(this);
        }
        // 将当前类作为 ApplicationModel 的父类
        internalApplicationModel = new ApplicationModel(this, true);
        internalApplicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig(internalApplicationModel, CommonConstants.DUBBO_INTERNAL_APPLICATION));
        internalApplicationModel.setModelName(CommonConstants.DUBBO_INTERNAL_APPLICATION);
    }
}

1.2.ApplicationModel

public class ApplicationModel extends ScopeModel {
    
    public ApplicationModel(FrameworkModel frameworkModel, boolean isInternal) {
        super(frameworkModel, ExtensionScope.APPLICATION, isInternal);
        this.frameworkModel = frameworkModel;
        frameworkModel.addApplication(this);
        initialize();
    }

    @Override
    protected void initialize() {
        super.initialize();
        // 将当前类作为 ModuleModel 的父类
        internalModule = new ModuleModel(this, true);
        this.serviceRepository = new ServiceRepository(this);
        // 加载 ApplicationInitListener类型 的扩展类
        ExtensionLoader<ApplicationInitListener> extensionLoader = this.getExtensionLoader(ApplicationInitListener.class);
        Set<String> listenerNames = extensionLoader.getSupportedExtensions();
        for (String listenerName : listenerNames) {
            extensionLoader.getExtension(listenerName).init();
        }
        initApplicationExts();
        // 加载 ScopeModelInitializer类型的 扩展类
        ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class);
        Set<ScopeModelInitializer> initializers = initializerExtensionLoader.getSupportedExtensionInstances();
        for (ScopeModelInitializer initializer : initializers) {
            // 马上执行扩展类的核心方法
            initializer.initializeApplicationModel(this);
        }
    }
}

1.3.ModuleModel

public class ModuleModel extends ScopeModel {
    
    public ModuleModel(ApplicationModel applicationModel, boolean isInternal) {
        super(applicationModel, ExtensionScope.MODULE, isInternal);
        this.applicationModel = applicationModel;
        applicationModel.addModule(this, isInternal);
        initialize();
    }

    @Override
    protected void initialize() {
        super.initialize();
        this.serviceRepository = new ModuleServiceRepository(this);
        this.moduleConfigManager = new ModuleConfigManager(this);
        this.moduleConfigManager.initialize();
        initModuleExt();
        // 加载 ScopeModelInitializer类型的扩展类
        ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class);
        Set<ScopeModelInitializer> initializers = initializerExtensionLoader.getSupportedExtensionInstances();
        for (ScopeModelInitializer initializer : initializers) {
            // 马上执行扩展类的核心方法
            initializer.initializeModuleModel(this);
        }
    }
}


2.ExtensionAccessor

利用Spi机制获取扩展类都是通过当前类先获取ExtensionLoader,后续通过ExtensionLoader加载对应的扩展类。

获取ExtensionLoader存在两种方式:

  1. 通过ExtensionDirector直接获取。
  2. 通过ExtensionAccessor间接获取。这种方式其实是通过ScopeModel间接获取到ExtensionDirector,其目的是利用ScopeModel初始化ExtensionDirector的parent属性。

如果是通过 ScopeModel 的子类获取扩展类,则必然是通过第二种方式获取ExtensionLoader。

public interface ExtensionAccessor {
    // 由 ExtensionDirector 以及 ScopeModel 类实现该方法
    ExtensionDirector getExtensionDirector();

    default <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        return this.getExtensionDirector().getExtensionLoader(type);
    }
    //支持获取特定name对应的扩展类
    default <T> T getExtension(Class<T> type, String name) {
        ExtensionLoader<T> extensionLoader = getExtensionLoader(type);
        return extensionLoader != null ? extensionLoader.getExtension(name) : null;
    }

    default <T> T getAdaptiveExtension(Class<T> type) {
        ExtensionLoader<T> extensionLoader = getExtensionLoader(type);
        return extensionLoader != null ? extensionLoader.getAdaptiveExtension() : null;
    }

    default <T> T getDefaultExtension(Class<T> type) {
        ExtensionLoader<T> extensionLoader = getExtensionLoader(type);
        return extensionLoader != null ? extensionLoader.getDefaultExtension() : null;
    }

}

内部方法参数type类型必须是被@SPI注解的类。

FrameworkModel、ApplicationModel、ModuleModel三者抽象父类ScopeModel实现了方法:

public interface ExtensionAccessor {
    ExtensionDirector getExtensionDirector();
}

2.1.ExtensionDirector

ExtensionDirector的作用其实就是获取扩展类的加载器ExtensionLoader。其实任何方式得到的扩展类的加载器都是ExtensionLoader,唯一的区别就是parent属性赋值与否。

ExtensionScope的取值涉及:FRAMEWORK、APPLICATION、MODULE、SELF。

public class ExtensionDirector implements ExtensionAccessor {
    private final ConcurrentMap<Class<?>, ExtensionLoader<?>> extensionLoadersMap = new ConcurrentHashMap<>(64);
    private final ConcurrentMap<Class<?>, ExtensionScope> extensionScopeMap = new ConcurrentHashMap<>(64);

    public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        ...
        // 1. find in local cache
        ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);

        ExtensionScope scope = extensionScopeMap.get(type);
        if (scope == null) {
            SPI annotation = type.getAnnotation(SPI.class);
            scope = annotation.scope();
            extensionScopeMap.put(type, scope);
        }
        // 如果 type 的scope范围是SELF,则直接返回 ExtensionLoader,并不需要考虑 属性parent的功能
        if (loader == null && scope == ExtensionScope.SELF) {
            // create an instance in self scope
            loader = createExtensionLoader0(type);
        }

        // 2. find in parent
        if (loader == null) {
            // 条件成立的条件是:必须是通过ScopeModel子类触发的扩展类加载
            if (this.parent != null) {
                // 递归的方式
                loader = this.parent.getExtensionLoader(type);
            }
        }

        // 3. create it
        if (loader == null) {
            // type & ScopeModel 的scope值必须匹配
            loader = createExtensionLoader(type);
        }

        return loader;
    }

    private <T> ExtensionLoader<T> createExtensionLoader(Class<T> type) {
        ExtensionLoader<T> loader = null;
        if (isScopeMatched(type)) {
            // if scope is matched, just create it
            loader = createExtensionLoader0(type);
        } else {
            // if scope is not matched, ignore it
        }
        return loader;
    }

    private <T> ExtensionLoader<T> createExtensionLoader0(Class<T> type) {
        checkDestroyed();
        ExtensionLoader<T> loader;
        extensionLoadersMap.putIfAbsent(type, new ExtensionLoader<T>(type, this, scopeModel));
        loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
        return loader;
    }

    private boolean isScopeMatched(Class<?> type) {
        // 当前ScopeModel对应的scope值是否与type spi注解中scope一致
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        return defaultAnnotation.scope().equals(scope);
    }
}

上述获取扩展类loader类似于jdk类加载器流程:

  • 抽象类ScopeModel三个子类存在非Java规范意义上的继承关系。
  • 任何一个ScopeModel的子类触发的loader流程优先获取属性parent的ExtensionLoader。
  • 目标接口type注解SPI其scope属性必须与当前ScopeModel的scope值一致方能引用当前parent的ExtensionLoader。否则继续向下寻找child对应的ExtensionLoader。
  • type的scope以及type的ExtensionLoader都存在集合类型的本地缓存。

 扩展类loader加载机制的作用:不同child需要相同的扩展类,只要scope值一样则可以由parent统一触发,避免child多次触发;child定制化的扩展类则通过scope值单独实现。


2.2.ExtensionLoader

利用ExtensionLoader获取目标接口扩展类的方式:

  1. 普通SPI实现原理:指定name获取接口的扩展类。根据接口名找到并解析配置文件,加载对应的扩展点实现类;类加载成功后就可以反射创建对象;对该对象完成IOC及AOP。

  2. 自适应SPI(Adaptive注解)实现原理:Javaassit 编译器对目标接口生成代理。代理类【type$Adaptive】执行@Adaptive方法触发目标方法执行。


2.2.1.普通SPI实现原理

public class ExtensionLoader<T> {

    private T createExtension(String name, boolean wrap) {
        //执行核心方法:利用不同策略获取扩展候选类类
        // 此处其实已经通过name得到候选类,例如利用javassist得到JavassistProxyFactory
        Class<?> clazz = getExtensionClasses().get(name);
        T instance = (T) extensionInstances.get(clazz);
        if (instance == null) {
            extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
            // 反射创建候选类实例
            instance = (T) extensionInstances.get(clazz);
            ...
        }
        if (wrap) {// 如果集合属性 cachedWrapperClasses 不为null,则需要通过代理方式增强目标方法功能,真正增强是通过wrap类型的候选类实现的
            List<Class<?>> wrapperClassesList = new ArrayList<>();
            if (cachedWrapperClasses != null) {
                wrapperClassesList.addAll(cachedWrapperClasses);
                wrapperClassesList.sort(WrapperComparator.COMPARATOR);
                Collections.reverse(wrapperClassesList);
            }

            if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
                for (Class<?> wrapperClass : wrapperClassesList) {
                    Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
                    ...
                    //如果 cachedWrapperClasses 集合中存在当前type对应的候选类,则依次返回wrapper类型的候选类
                    // 实例化wrapperClass:1.获取存在type构造参数的构造器;2.将type接口类型的实现子类通过构造方法属性赋值
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
        }
        ...
        return instance;
    }
    
}

 2.2.1.1.IOC

 场景:SPI接口中通过set开头的方法注入其他SPI接口作为属性。

  1. set方法注入条件:set开头,参数只有一个并且public修饰。
  2. set方法上没有使用 DisableInject 注解。
  3. set 方法是在ScopeModelAware 系列中声明的也不能注入。
private T createExtension(String name, boolean wrap) {
  
  // 1️⃣.加载扩展点实现类,得到class对象
  Class<?> clazz = getExtensionClasses().get(name);
  
  // 2️⃣.这里通过反射调用空参构造函数,完成实例化
  T instance = (T) EXTENSION_INSTANCES.get(clazz);
  if (instance == null) {  
    EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
    instance = (T) EXTENSION_INSTANCES.get(clazz);
  }

  // 3️⃣.IOC
  injectExtension(instance);

  // 4️⃣.AOP
  if (wrap) {
    // .....
  }
  
  // 5️⃣.扩展点生命周期,进一步完成初始化
  initExtension(instance);
  return instance;
}
public class ExtensionLoader<T> {
    private final ExtensionInjector injector;

    private T injectExtension(T instance) {

        if (injector == null) {
            return instance;
        }
        // 遍历 当前SPI接口存在的全部方法
        for (Method method : instance.getClass().getMethods()) {
            if (!isSetter(method)) {// 如果方法不存在set方法,则表明不存在IOC注入功能
                continue;
            }
            //如果方法存在DisableInject注解,则表明不存在IOC注入功能
            if (method.isAnnotationPresent(DisableInject.class)) {
                continue;
            }
            // "set"方法只存在一个SPI接口类型的变量
            Class<?> pt = method.getParameterTypes()[0];
            if (ReflectUtils.isPrimitives(pt)) {
                continue;
            }
            // 从"set"方法名中获取 SPI接口 的名,例如setProtocol,表明SPI接口名为protocol
            String property = getSetterProperty(method);
            // 从 Dubbo IOC容器中 获取 beanName 为 property的 bean
            Object object = injector.getInstance(pt, property);
            if (object != null) {// 通过反射调用注入目标bean
                method.invoke(instance, object);
            }
        }
        return instance;
    }
}

2.2.1.2.AOP

实现AOP功能的前提条件:

  1. SPI接口的实现类至少存在两个扩展类,一个是原始类,另一个是对原始类增强的wrappr类。
  2. wrappr类的类名最好以wrappr作为前缀。
  3. wrappr类存在有参构造方法,并且参数类型SPI接口类型,有且仅有一个参数。
  4. wrappr类中目标方法是增强方法。
public class ExtensionLoader<T> {
    //增强之前,必须存在SPI接口的扩展类
    Class<?> clazz = getExtensionClasses().get(name);
    if (clazz == null || unacceptableExceptions.contains(name)) {
        throw findException(name);
    }
    ...
    if (wrap) {
        // SPI接口的扩展类必须同时存在wrapper类型的扩展类,用于增强目标类
        List<Class<?>> wrapperClassesList = new ArrayList<>();
        if (cachedWrapperClasses != null) {
            wrapperClassesList.addAll(cachedWrapperClasses);
            wrapperClassesList.sort(WrapperComparator.COMPARATOR);
            Collections.reverse(wrapperClassesList);
        }

        if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
            for (Class<?> wrapperClass : wrapperClassesList) {
                Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
                boolean match = (wrapper == null) ||
                    ((ArrayUtils.isEmpty(wrapper.matches()) || ArrayUtils.contains(wrapper.matches(), name)) &&
                        !ArrayUtils.contains(wrapper.mismatches(), name));
                if (match) {
                    // 此处就是对 增强类的实例化,注意:反射方式实例化时构造器必须在SPI接口类型的参数。
                    // 返回的实例也是SPI接口的扩展类,只不过该扩展类内部通过 SPI接口 回调了目标方法
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                    instance = postProcessAfterInitialization(instance, name);
                }
            }
        }
    }
    return instance;
}


2.2.2.自适应SPI(Adaptive注解)实现原理

Adaptive 机制可以指定想要加载的扩展名,也可以不指定。若不指定则直接加载默认的扩展类。即其会自动匹配做到自适应。其是通过@Adaptive注解实现的。

该SPI机制的前提:

  1. 目标接口必须存在@Adaptive方法
  2. @Adaptive方法首个参数必须是org.apache.dubbo.common.URL类型。
public class ExtensionLoader<T> {
    private final Class<?> type;//目标接口
    private Class<?> createAdaptiveExtensionClass() {
        ClassLoader classLoader = type.getClassLoader();
        // 目标接口type对应的代理类字符串形式
        String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
        org.apache.dubbo.common.compiler.Compiler compiler = extensionDirector.getExtensionLoader(
            org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(type, code, classLoader);
    }
}

如上所示自适应SPI原理其实就是对目标接口type进行Javaassit编译生成代理类,如下所示:

public class Order$Adaptive implements net.dubbo.provider.spi.adaptive.Order {
    //非@Adaptive方法
    public java.lang.String way() {
        throw new UnsupportedOperationException("The method public abstract java.lang.String net.dubbo.provider.spi.adaptive.Order.way() of interface net.dubbo.provider.spi.adaptive.Order is not adaptive method!");
    }
    //@Adaptive方法
    public java.lang.String pay(org.apache.dubbo.common.URL arg0) {
        if (arg0 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg0;
        // order:目标接口名。wechat:接口@SPI指定的扩展类名。
        // 从 URL 中获取  order 的value,默认值 @SPI指定的扩展类名
        String extName = url.getParameter("order", "wechat");
        if (extName == null)throw new IllegalStateException("Failed to get extension (net.dubbo.provider.spi.adaptive.Order) name from url (" + url.toString() + ") use keys([order])");
        ScopeModel scopeModel = ScopeModelUtil.getOrDefault(url.getScopeModel(), net.dubbo.provider.spi.adaptive.Order.class);
        // 通过 普通SPI 机制获取目标接口利用 @SPI注解指定的扩展类
        Order extension = (Order) scopeModel.getExtensionLoader(Order.class).getExtension(extName);
        return extension.pay(arg0);
    }
}

所以综上所述,通过在代理类调用目标方法时可以改变 @SPI注解指定的扩展类名。

非@Adaptive方法通过代理类执行目标方法就直接抛出异常


2.3.LoadingStrategy

Dubbo SPI 的配置做出了改进,在 Dubbo 中有三种不同的目录可以存放 SPI 配置,用途也不同,优先级由低到高如下所示:

  • META-INF/services/ 目录:此目录配置文件用于兼容 JDK SPI 【ServicesLoadingStrategy】。
  •  META-INF/dubbo/ 目录:此目录用于存放用户自定义 SPI 配置文件【DubboLoadingStrategy】。
  • META-INF/dubbo/internal/ 目录:此目录用于存放 Dubbo 内部使用的 SPI 配置文件【DubboInternalLoadingStrategy】。

其中,只有ServicesLoadingStrategy在其对应目录文件中是不支持kv形式的。


3. ScopeModelInitializer

 

public interface ScopeModelInitializer {

    void initializeFrameworkModel(FrameworkModel frameworkModel);

    void initializeApplicationModel(ApplicationModel applicationModel);

    void initializeModuleModel(ModuleModel moduleModel);
}

ScopeModelInitializer存在各种实现类,并且在ScopeModel子类的构造器中完成ScopeModelInitializer相关子类的实例化。其中ConfigScopeModelInitializer主要功能是完成接口Deployer子类的实例化。


4.ExtensionInjector

@SPI(scope = ExtensionScope.SELF)
public interface ExtensionInjector extends ExtensionAccessorAware {
    @Override
    default void setExtensionAccessor(ExtensionAccessor extensionAccessor) {
    }
}

该类型接口实现类:

  1. ScopeBeanExtensionInjector:从Dubbo自己设计的IOC容器中获取。
  2. SpringExtensionInjector:从Spring IOC容器中获取目标bean。
  3. SpiExtensionInjector:利用SPI机制加载注入的目标接口实现类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值