DubboSPI使用方式以及源码详细解读

DubboSPI流程图

img

为什么Dubbo要自己实现SPI

java spi 会一次性实例化扩展点所有实现,机制并不能根据获取自己想要的类

获取一个类的实现对象

javaSPI 具有局限性:
1、没法给实现类起别名
2、没法实现包装类。类似AOP的原理
3、没法实现自动注入
4、没法实现按需加载。一次性就会加载配置文件中配置的所有类

Dubbo SPI的改进

根据需要实例化扩展点

增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。

DubboSPI使用

1、@SPI 注解需要打在接口上(“可以传入value”,默认找的实现类)

2、META-INFO.dubbo下需要创建一个与接口全类名相同的文件

3、配置文件内需要配置实现类全类名

4、Wrapper类(类似AOP)需要通过有参构造方法来注入

Wrapper

Dubbo通过Wrapper实现AOP的方法

Wrapper机制,即扩展点自动包装。Wrapper 类同样实现了扩展点接口,但是 Wrapper 不是扩展点的真正实现。它的用途主要是用于从 ExtensionLoader 返回扩展点时,包装在真正的扩展点实现外。即从 ExtensionLoader 中返回的实际上是 Wrapper 类的实例,Wrapper 持有了实际的扩展点实现类。 扩展点的 Wrapper 类可以有多个,也可以根据需要新增。 通过 Wrapper 类可以把所有扩展点公共逻辑移至 Wrapper 中。新加的 Wrapper 在所有的扩展点上添加了逻辑,有些类似 AOP,即 Wrapper 代理了扩展点。

Wrapper的规范 Wrapper 机制不是通过注解实现的,而是通过一套 Wrapper 规范实现的。 Wrapper 类在定义时需要遵循如下规范。

  • 该类要实现 SPI 接口
  • 该类中要有 SPI 接口的引用
  • 该类中必须含有一个含参的构造方法且参数只能有一个类型为SPI接口
  • 在接口实现方法中要调用 SPI 接口引用对象的相应方法
  • 该类名称以 Wrapper 结尾

Dubbo 3.1.2 版本spi源码阅读

dubbo 3版本对spi做了优化,在以前版本的基础上,对spi添加了模块化工作范围(scope)

借助SPI实现相关探针,使得生命周期可以被容器感知,即生命周期与容器对齐。

大致梳理流程:

1、根据指定的接口加载配置文件

2、根据配置文件加载对应的类 缓存起来

3、根据加载的类按需反射生成对象 缓存起来

4、完成自动注入

ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Test.class);

dubbo3版本使用**ExtensionLoader**更换成 **ApplicationModel.defaultModel().getExtensionLoader(Test.class)**根据工作范围获取ExtensionLoader

getExtension

public T getExtension(String name) {
    //多传了个参数wrap为true调用另外一个重载的方法
    T extension = getExtension(name, true);
    if (extension == null) {
        throw new IllegalArgumentException("Not find extension: " + name);
    }
    return extension;
}
public T getExtension(String name, boolean wrap) {
		//检查扩展加载器是否已被销毁
        checkDestroyed();
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        //扩展名字为true则加载默认扩展
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        //非wrap类型则将缓存的扩展名字key加上_origin后缀
        //wrap是aop机制 这个origin在aop里面可以称为切点,下面的wrap扩展可以称为增强通知的类型,普通扩展和wrap扩展的扩展名字是一样的
        String cacheKey = name;
        if (!wrap) {
            cacheKey += "_origin";
        }
        //从cachedInstances缓存中查询
        final Holder<Object> holder = getOrCreateHolder(cacheKey);
        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;
    }
加载默认扩展 getDefaultExtension()
public T getDefaultExtension() {
    //加载扩展类型对应的所有扩展SPI实现类型,在加载所有扩展实现类型的时候会缓存这个扩展的默认实现类型
    //将对象缓存在cachedDefaultName中
    getExtensionClasses();
    // cachedDefaultName 是否已经更新或者为true,避免死循环
    if (StringUtils.isBlank(cachedDefaultName) || "true".equals(cachedDefaultName)) {
        return null;
    }
    // 根据 cachedDefaultName 加载
    return getExtension(cachedDefaultName);
}

getExtensionClasses()

private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    try {
                        // 核心,加载类, 解析在下面
                        classes = loadExtensionClasses();
                    } catch (InterruptedException e) {
                        logger.error(COMMON_ERROR_LOAD_EXTENSION, "", "", "Exception occurred when loading extension class (interface: " + type + ")", e);
                        throw new IllegalStateException("Exception occurred when loading extension class (interface: " + type + ")", e);
                    }
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }

createExtension(name, wrap);

private T createExtension(String name, boolean wrap) {
    //扫描所有jar中的实现,获取对应扩展名字的Class对象  getExtensionClasses()解释在上面
    Class<?> clazz = getExtensionClasses().get(name);
    if (clazz == null || unacceptableExceptions.contains(name)) {
        throw findException(name);
    }
    try {
        // 如果创建过了clazz对象 直接从缓存中取
        T instance = (T) extensionInstances.get(clazz);
        if (instance == null) {
            // 第一次创建扩展对象后,缓存起来,对应上面从缓存中取
            extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
            instance = (T) extensionInstances.get(clazz);
            instance = postProcessBeforeInitialization(instance, name);
            // 注入自适应扩展方法
            injectExtension(instance);
            instance = postProcessAfterInitialization(instance, name);
        }
    	// AOP实现warp 代理类 ,默认开启
        if (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);
                    // wrapper 不存在 
                    // matches 包含name 
                    // mismatches不包含当前扩展 name
                    boolean match = (wrapper == null) ||
                        ((ArrayUtils.isEmpty(wrapper.matches()) || ArrayUtils.contains(wrapper.matches(), name)) &&
                            !ArrayUtils.contains(wrapper.mismatches(), name));
                    // 是否需要注入
                    if (match) {
                        // 核心 创建wrapper 类型对象, 然后根据构造函数注入,然后返回给instance 
                    	// newInstance 创建对象时,如果有参数构造函数,直接传入参数,就实现了根据有参构造创建对象
                        //  实现 返回的instance 编程包装类型
                        instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                        instance = postProcessAfterInitialization(instance, name);
                    }
                }
            }
        }

        // Warning: After an instance of Lifecycle is wrapped by cachedWrapperClasses, it may not still be Lifecycle instance, this application may not invoke the lifecycle.initialize hook.
        // 如果 instance 是Lifecycle 类型的对象 ,执行 Lifecycle 的  initialize(); 方法
        initExtension(instance);
        return instance;
    } catch (Throwable t) {
        throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
            type + ") couldn't be instantiated: " + t.getMessage(), t);
    }
private void initExtension(T instance) {
        if (instance instanceof Lifecycle) {
            Lifecycle lifecycle = (Lifecycle) instance;
            lifecycle.initialize();
        }
    }

injectExtension(T instance) 依赖注入

private T injectExtension(T instance) {
        if (injector == null) {
            return instance;
        }

        try {
            for (Method method : instance.getClass().getMethods()) {
                // 不是以set开头 方法 返回
                if (!isSetter(method)) {
                    continue;
                }
                /**
                 * Check {@link DisableInject} to see if we need auto-injection for this property
                 */
                // 如果有 禁用注入注解 DisableInject 结束
                if (method.isAnnotationPresent(DisableInject.class)) {
                    continue;
                }

                // When spiXXX implements ScopeModelAware, ExtensionAccessorAware,
                // the setXXX of ScopeModelAware and ExtensionAccessorAware does not need to be injected
                if (method.getDeclaringClass() == ScopeModelAware.class) {
                    continue;
                }
                if (instance instanceof ScopeModelAware || instance instanceof ExtensionAccessorAware) {
                    if (ignoredInjectMethodsDesc.contains(ReflectUtils.getDesc(method))) {
                        continue;
                    }
                }

                Class<?> pt = method.getParameterTypes()[0];
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }

                try {
                    String property = getSetterProperty(method);
                    Object object = injector.getInstance(pt, property);
                    if (object != null) {
                        method.invoke(instance, object);
                    }
                } catch (Exception e) {
                    logger.error(COMMON_ERROR_LOAD_EXTENSION, "", "", "Failed to inject via method " + method.getName()
                        + " of interface " + type.getName() + ": " + e.getMessage(), e);
                }
            }
        } catch (Exception e) {
            logger.error(COMMON_ERROR_LOAD_EXTENSION, "", "", e.getMessage(), e);
        }
        return instance;
    }

怎么实现的Wrapper包装

java 反射基础知识

createExtension方法 中 instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));newInstance(instance) 即 根据有参构造方法,同时传入 instance 创建对象,以次方式实现了用构造方法传入包装对象

LoadingStrategy 及 loadExtensionClasses()

LoadingStrategy 是 加载策略 在 loadExtensionClasses() 加载配置文件方法中的优化使用

loadExtensionClasses()

dubbo 以前加载配置文件时通过如下方式

private Map<String, Class<?>> loadExtensionClasses() {
    cacheDefaultExtensionName();
    Map<String, Class<?>> extensionClasses = new HashMap<>();
    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;
}

加载三个位置的 “META-INF/dubbo/internal/”,“META-INF/dubbo/”,“META-INF/services/” 文件

dubbo通过 LoadingStrategy 定义了一个加载策略,通过遍历加载策略的形式,去加载spi扩展文件,实现了加载扩展文件的可扩展性 (不是dubbo3的优化)

private Map<String, Class<?>> loadExtensionClasses() throws InterruptedException {
    checkDestroyed();
    cacheDefaultExtensionName();

    Map<String, Class<?>> extensionClasses = new HashMap<>();
    // 遍历加载策略类
    for (LoadingStrategy strategy : strategies) {
        loadDirectory(extensionClasses, strategy, type.getName());

        // compatible with old ExtensionFactory
        // 兼容旧版本
        if (this.type == ExtensionInjector.class) {
            loadDirectory(extensionClasses, strategy, ExtensionFactory.class.getName());
        }
    }

    return extensionClasses;
}
加载LoadingStrategy

LoadingStrategy 是采用java的spi方式

private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();
private static LoadingStrategy[] loadLoadingStrategies() {
        // 通过ServiceLoader.load方法  (java spi 方式)来加载LoadingStrategy的扩展
        return stream(load(LoadingStrategy.class).spliterator(), false)
            .sorted()
            .toArray(LoadingStrategy[]::new);
}

META-INF/services/org.apache.dubbo.common.extension.LoadingStrategy

org.apache.dubbo.common.extension.DubboInternalLoadingStrategy
org.apache.dubbo.common.extension.DubboLoadingStrategy
org.apache.dubbo.common.extension.ServicesLoadingStrategy

img

loadDirectoryInternal 方法详解

fileName就是LoadingStrategy所指定的目录 + 接口的全限定名,这里就解释了为什么实现类需要写在类全限定名的文件里

private void loadDirectoryInternal(Map<String, Class<?>> extensionClasses, LoadingStrategy loadingStrategy, String type) throws InterruptedException {
    //LoadingStrategy所指定的目录 + 接口的全限定名
    String fileName = loadingStrategy.directory() + type;
    try {
        List<ClassLoader> classLoadersToLoad = new LinkedList<>();
        
        // try to load from ExtensionLoader's ClassLoader first
        // 是否需要在加载ExtensionLoader之前 先用 ClassLoader 加载 
       
        if (loadingStrategy.preferExtensionClassLoader()) {
            ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
            if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
                classLoadersToLoad.add(extensionLoaderClassLoader);
            }
        }

        //有些spi只通过dubbo框架实现,扫描多类加载器资源可能会导致应用程序启动非常慢
        if (specialSPILoadingStrategyMap.containsKey(type)) {
            String internalDirectoryType = specialSPILoadingStrategyMap.get(type);
            //skip to load spi when name don't match
            if (!LoadingStrategy.ALL.equals(internalDirectoryType)
                && !internalDirectoryType.equals(loadingStrategy.getName())) {
                return;
            }
            classLoadersToLoad.clear();
            classLoadersToLoad.add(ExtensionLoader.class.getClassLoader());
        } else {
            // load from scope model
            Set<ClassLoader> classLoaders = scopeModel.getClassLoaders();

            if (CollectionUtils.isEmpty(classLoaders)) {
                // getSystemResources 去指定的文件, 加载返回一个URL对象 
                Enumeration<java.net.URL> resources = ClassLoader.getSystemResources(fileName);
                if (resources != null) {
                    while (resources.hasMoreElements()) {
                        // 根据 '=' 切割 然后加载类
                        loadResource(extensionClasses, null, resources.nextElement(), loadingStrategy.overridden(),
                            loadingStrategy.includedPackages(),
                            loadingStrategy.excludedPackages(),
                            loadingStrategy.onlyExtensionClassLoaderPackages());
                    }
                }
            } else {
                classLoadersToLoad.addAll(classLoaders);
            }
        }

        Map<ClassLoader, Set<java.net.URL>> resources = ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad);
        resources.forEach(((classLoader, urls) -> {
            loadFromClass(extensionClasses, loadingStrategy.overridden(), urls, classLoader,
                loadingStrategy.includedPackages(),
                loadingStrategy.excludedPackages(),
                loadingStrategy.onlyExtensionClassLoaderPackages());
        }));
    } catch (InterruptedException e) {
        throw e;
    } catch (Throwable t) {
        logger.error(COMMON_ERROR_LOAD_EXTENSION, "", "", "Exception occurred when loading extension class (interface: " +
            type + ", description file: " + fileName + ").", t);
    }
}

loadresource()=>loadClass(

private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
                           boolean overridden) {
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error occurred when loading extension class (interface: " +
                type + ", class line: " + clazz.getName() + "), class "
                + clazz.getName() + " is not subtype of interface.");
        }
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            // 如果类有Adaptive注解,缓存类,优先级最高
            cacheAdaptiveClass(clazz, overridden);
        } else if (isWrapperClass(clazz)) {
            // 如果是包装类 缓存Wrapper
            cacheWrapperClass(clazz);
        } else {
            if (StringUtils.isEmpty(name)) {
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                }
            }

            String[] names = NAME_SEPARATOR.split(name);
            if (ArrayUtils.isNotEmpty(names)) {
                // 如果类中包含 Activate 注解 ,添加到缓存
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                    cacheName(clazz, n);
                    // 类名和实例,存入之前的map
                    saveInExtensionClass(extensionClasses, clazz, n, overridden);
                }
            }
        }
    }

Dubbo中的Adaptive机制源码解析

获取方法ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()

@Adaptive 放在类上

如果找到了@Adaptive标注的实现类,直接返回然后实例化 在getAdaptiveExtensionClass() 源码中有解释

如果没有找到@Adaptive标注的实现类,则会通过代理生成一个类并实例化返回

@Adaptive 放在方法上

上面如果没有找到@Adaptive标注的类。则会去动态代理生成一个类。@Adaptive在方法上的作用就体现出来了

1、加了@Adaptive 的方法会被代理。其他的方法则默认方法体都是抛异常

2、加了@Adaptive 的方法的形参上必须有URL类型的参数或者对象有getURL的方法。可以看代理类的源代码。

getAdaptiveExtension()

public T getAdaptiveExtension() {
        checkDestroyed();
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError != null) {
                throw new IllegalStateException("Failed to create adaptive instance: " +
                    createAdaptiveInstanceError.toString(),
                    createAdaptiveInstanceError);
            }

            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        // 核心 先从缓存获取,缓存没有就创建
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        }

        return (T) instance;
    }
private T createAdaptiveExtension() {
        try {
            T instance = (T) getAdaptiveExtensionClass().newInstance();
            instance = postProcessBeforeInitialization(instance, null);
            injectExtension(instance);
            instance = postProcessAfterInitialization(instance, null);
            initExtension(instance);
            return instance;
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }

getAdaptiveExtensionClass()

private Class<?> getAdaptiveExtensionClass() {
    // 去加载扩展类
    getExtensionClasses();
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    // 如果没有adaptive 注解修饰的类,用动态代理创建一个代理类
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

Protocol生成代理类内容

package org.apache.dubbo.rpc;

import java.util.List;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.model.ScopeModelUtil;

public class Protocol$Adaptive implements Protocol {
    @Override
    public void destroy() {
        throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    @Override
    public int getDefaultPort() {
        throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public List getServers() {
        throw new UnsupportedOperationException("The method public default java.util.List org.apache.dubbo.rpc.Protocol.getServers() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public Exporter export(Invoker invoker) throws RpcException {
        String string;
        if (invoker == null) {
            throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        }
        if (invoker.getUrl() == null) {
            throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        }
        URL uRL = invoker.getUrl();
        String string2 = string = uRL.getProtocol() == null ? "dubbo" : uRL.getProtocol();
        if (string == null) {
            throw new IllegalStateException(new StringBuffer().append("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (").append(uRL.toString()).append(") use keys([protocol])").toString());
        }
        ScopeModel scopeModel = ScopeModelUtil.getOrDefault(uRL.getScopeModel(), Protocol.class);
        Protocol protocol = scopeModel.getExtensionLoader(Protocol.class).getExtension(string);
        return protocol.export(invoker);
    }

    public Invoker refer(Class clazz, URL uRL) throws RpcException {
        String string;
        if (uRL == null) {
            throw new IllegalArgumentException("url == null");
        }
        URL uRL2 = uRL;
        String string2 = string = uRL2.getProtocol() == null ? "dubbo" : uRL2.getProtocol();
        if (string == null) {
            throw new IllegalStateException(new StringBuffer().append("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (").append(uRL2.toString()).append(") use keys([protocol])").toString());
        }
        ScopeModel scopeModel = ScopeModelUtil.getOrDefault(uRL2.getScopeModel(), Protocol.class);
        Protocol protocol = scopeModel.getExtensionLoader(Protocol.class).getExtension(string);
        return protocol.refer(clazz, uRL);
    }
}

@Activte激活拓展点

有点像Spring当中的Conditional

@ConditionalOnBean(XXX.class)只有XXX这个类在容器中存在,才会执行修饰的方法

  • group() 指定组条件。框架SPI定义了有效的组值。
  • value() 指定URL条件中的参数键。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Activate {

    String[] group() default {};


    String[] value() default {};

    @Deprecated
    String[] before() default {};

    @Deprecated
    String[] after() default {};

    int order() default 0;

使用

@Activate(group = {Constants.PROVIDER,Constants.CONSUMER},order = 5,value = “value”)

ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Filter.class);
URL url=new URL("","",3);
url=url.addParameter("key", "value");
List list=extensionLoader.getActivateExtension(url,"key",Constants.PROVIDER);

url 中是否有 满足有values 的参数

是否满足group 相等

注意点,如果一个类Activate 注解中 中的同时添加了value 和group 那么必须要同时满足

group分组的满足条件

  • 获取扩展点时没传group 默认满足条件
  • Activate注解中的groups 不为空且包含传入的group时 满足条件

源码

getActivateExtension(URL url, String key, String group)
/**
 *  
 *
 * @param url   url
 * @param key   获取url参数键 
 * @param group group 用于筛选的分组,比如使用此参数来区分消费者还是提供者(consumer,provider)
 * @return 已激活的扩展列表。
 */
public List<T> getActivateExtension(URL url, String key, String group) {
    //获取url指定的参数值
    String value = url.getParameter(key);
    //调用重载的方法
    return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);
}
getActivateExtension(URL url, String[] values, String group)
public List<T> getActivateExtension(URL url, String[] values, String group) {
        checkDestroyed();
        // solve the bug of using @SPI's wrapper method to report a null pointer exception.
    //TreeMap 有序即可,对扩展排序
    Map<Class<?>, T> activateExtensionsMap = new TreeMap<>(activateComparator);
        List<String> names = values == null ? new ArrayList<>(0) : asList(values);
        Set<String> namesSet = new HashSet<>(names);
        if (!namesSet.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
            if (cachedActivateGroups.size() == 0) {
                synchronized (cachedActivateGroups) {
                    // cache all extensions
                    if (cachedActivateGroups.size() == 0) {
                        // 加载对应扩展类
                        getExtensionClasses();
                        for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
                            String name = entry.getKey();
                            Object activate = entry.getValue();

                            String[] activateGroup, activateValue;
                        	// 遍历之前缓存的map  获取group 和value
                            if (activate instanceof Activate) {
                                activateGroup = ((Activate) activate).group();
                                activateValue = ((Activate) activate).value();
                            } else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
                                activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
                                activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
                            } else {
                                continue;
                            }
                            // 根据扩展名称缓存分组
                            cachedActivateGroups.put(name, new HashSet<>(Arrays.asList(activateGroup)));
                            String[][] keyPairs = new String[activateValue.length][];
                            for (int i = 0; i < activateValue.length; i++) {
                                if (activateValue[i].contains(":")) {
                                    keyPairs[i] = new String[2];
                                    String[] arr = activateValue[i].split(":");
                                    keyPairs[i][0] = arr[0];
                                    keyPairs[i][1] = arr[1];
                                } else {
                                    keyPairs[i] = new String[1];
                                    keyPairs[i][0] = activateValue[i];
                                }
                            }
                            cachedActivateValues.put(name, keyPairs);
                        }
                    }
                }
            }

            // traverse all cached extensions
            //遍历所有激活的扩展名字和扩展分组集合
            cachedActivateGroups.forEach((name, activateGroup) -> {
                //筛选当前扩展的扩展分组与激活扩展的扩展分组是否可以匹配
                if (isMatchGroup(group, activateGroup)
                    && !namesSet.contains(name)
                    && !namesSet.contains(REMOVE_VALUE_PREFIX + name)
//如果在Active注解中配置了value则当指定的键出现在URL的参数中时,激活当前扩展名。 
//如果未配置value属性则默认都是匹配的(cachedActivateValues中不存在对应扩展名字的缓存的时候默认为true
                    && isActive(cachedActivateValues.get(name), url)) {

                    activateExtensionsMap.put(getExtensionClass(name), getExtension(name));
                }
            });
        }

        if (namesSet.contains(DEFAULT_KEY)) {
            // will affect order
            // `ext1,default,ext2` means ext1 will happens before all of the default extensions while ext2 will after them
            ArrayList<T> extensionsResult = new ArrayList<>(activateExtensionsMap.size() + names.size());
            for (String name : names) {
                if (name.startsWith(REMOVE_VALUE_PREFIX)
                    || namesSet.contains(REMOVE_VALUE_PREFIX + name)) {
                    continue;
                }
                if (DEFAULT_KEY.equals(name)) {
                    extensionsResult.addAll(activateExtensionsMap.values());
                    continue;
                }
                if (containsExtension(name)) {
                    extensionsResult.add(getExtension(name));
                }
            }
            return extensionsResult;
        } else {
            // add extensions, will be sorted by its order
            for (String name : names) {
                if (name.startsWith(REMOVE_VALUE_PREFIX)
                    || namesSet.contains(REMOVE_VALUE_PREFIX + name)) {
                    continue;
                }
                if (DEFAULT_KEY.equals(name)) {
                    continue;
                }
                if (containsExtension(name)) {
                    activateExtensionsMap.put(getExtensionClass(name), getExtension(name));
                }
            }
            return new ArrayList<>(activateExtensionsMap.values());
        }
    }
isMatchGroup(String group, Set groups)
private boolean isMatchGroup(String group, Set<String> groups) {
        // 获取扩展点时 没传group 默认满足条件
        if (StringUtils.isEmpty(group)) {
            return true;
        }
        // Activate注解中的groups 不为空且包含传入的group时 满足条件
        if (CollectionUtils.isNotEmpty(groups)) {
            return groups.contains(group);
        }
        return false;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值