zoukankan      html  css  js  c++  java
  • ExtensionLoader源码分析

    Dubble扩展点核心类ExtensionLoader

    Dubbo 的扩展点加载从 JDK 标准的 SPI (Service Provider Interface) 扩展点发现机制加强而来。
    Dubbo 改进了 JDK 标准的 SPI 的以下问题:

    1. JDK 标准的 SPI 会⼀次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源;
    2. 如果扩展点加载失败,连扩展点的名称都拿不到了。⽐如:JDK 标准的 ScriptEngine,通过getName()获取脚本类型的名称,但如果 RubyScriptEngine 因为所依赖的 jruby.jar 不存在,导致 RubyScriptEngine类加载失败,这个失败原因被吃掉了,和 ruby对应不起来,当用户执行ruby 脚本时,会报不支持ruby,而不是真正失败的原因;
    3. 增加了对扩展点 IoC 和 AOP 的支持,⼀个扩展点可以直接 setter 注⼊其它扩展点。

    1、ExtensionLoader属性

    先看ExtensionLoader类内部的静态变量

    private static final String SERVICES_DIRECTORY = "META-INF/services/";
    
    private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
    
    private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
    

    这三个变量标识的是ExtensionLoader查找扩展类的路径,分别是“META-INF/services/”、“META-INF/dubbo/”和“META-INF/dubbo/internal/”。

    接下来是两个重要的静态变量,所有ExtensionLoader实例都共享这两个变量的值。

    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
    
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
    

    EXTENSION_LOADERS静态变量存储的是SPI接口类和ExtensionLoader对象的映射关系。Dubble会为每一个SPI接口都会创建一个ExtensionLoader对象,并保存到EXTENSION_LOADERS变量中。

    EXTENSION_INSTANCES静态变量存储的是每个SPI接口的多个实现类和对应实例之间的关系。因此java进程中通常对应接口实现类对象是单例的。

    2、ExtensionFactory 与 ExtensionLoader的关系

    • 每个接口Class会创建对应的ExtensionLoader对象
    • 每个ExtensionLoader<?>对象持有个的ExtensionFactory属性是同一个对象;ExtensionFactory接口对应的ExtensionLoader对象持有的ExtensionFactory属性是null。
    • 每个ExtensionLoader<?>对象持有个的ExtensionFactory属性 是AdaptiveExtensionFactory类的实例
    • AdaptiveExtensionFactory类对象在整个应用运行中只有一个,为啥不采用静态属性?个人思考是因为 ExtensionLoader 对象 不需要ExtensionFactory属性

    我们定义测试类,用于断点追踪和查看执行效果。

    public static void main(String[] args) {
        PrintService printService = ExtensionLoader.getExtensionLoader(PrintService.class).getDefaultExtension();
        printService.print();
    }
    

    进入getExtensionLoader方法,代码如下:

    private ExtensionLoader(Class<?> type) {
        this.type = type; //给type赋值
        //给objectFactory赋值
        objectFactory = (type == ExtensionFactory.class ? null :                               ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
    
    private static <T> boolean withExtensionAnnotation(Class<T> type) {
        return type.isAnnotationPresent(SPI.class);
    }
    
    //通过接口的Class获取到对应的ExtensionLoader实例
    @SuppressWarnings("unchecked")
    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!");
        }
        //接口需要被@SPI注解标注,代码看上面
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type(" + type +") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }
    
        //根据类型尝试先从EXTENSION_LOADERS静态变量中获取对应的ExtensionLoader,就是先查缓存
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            //EXTENSION_LOADERS中获取不到,在EXTENSION_LOADERS中添加映射关系,new ExtensionLoader时,需要给type属性和objectFactory赋值
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            //重新从EXTENSION_LOADERS静态变量中获取对应的ExtensionLoader
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }
    

    这里需要注意构造函数中的逻辑:给objectFactory赋值。

    objectFactory = (type == ExtensionFactory.class ? null :                               ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    

    当传入的type是ExtensionFactory类时,objectFactory为null;当传入的是其他接口时,需要首先获取到ExtensionFactory接口对应的ExtensionLoader对象,再通过这个对象调用getAdaptiveExtension()方法获取到AdaptiveExtensionFactory类对象,最后赋值给objectFactory。逻辑有个小弯,仔细思考。

    3、缓存变量

    前面提到,Dubbo SPI改进了Java SPI机制,提供惰性加载机制。在实现上启动的时候加载类对象之后,并没有立刻创建这些类对象的实例,而是把他们存放在内存中缓存起来,接下来先来总结一下这些变量。

    属性 描述
    ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES 扩展类和对应的类加载器映射关系
    ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES 扩展类和实例映射关系
    ConcurrentMap<Class<?>, String> cachedNames 扩展类和扩展名称映射关系
    Holder<Map<String, Class<?>>> cachedClasses 扩展名称和扩展类类型映射关系
    Map<String, Object> cachedActivates 扩展名称和自动激活扩展类映射关系
    ConcurrentMap<String, Holder> cachedInstances 扩展名称和扩展类实例映射关系
    Holder cachedAdaptiveInstance 自适应扩展类实例缓存
    Class<?> cachedAdaptiveClass 自适应扩展类
    Set<Class<?>> cachedWrapperClasses 包装扩展类集合

    其中,cachedClasses并不包括cachedAdaptiveClass和cachedWrapperClasses。实际上,cachedClasses + cachedAdaptiveClasses + cachedWrapperClasses才是所有的扩展类实现。在EXTENSION_INSTANCES中存放的是扩展类直接生成的对象,没有经过后续的依赖注入、进行类包装等后续处理。

    下面,来看一下ExtensionLoader中重要的三个方法,分别是getExtension方法、getAdaptiveExtension方法和getActivaeExtension方法,分别用于获取普通扩展类,获取自适应扩展类和获取激活扩展性。

    4、getExtension方法实现原理

    getExtension(String name)方法是整个扩展类中最核心的方法,实现了一个完整的普通扩展类加载过程。在加载中的每一步都会检查缓存中是否存在所需要的数据,如果有则直接从缓存中读取,没有则重新加载。这个方法每次只会根据名称返回一个扩展点实现类。初始化过程分为四步:

    1. 读取SPI对应路径下的配置文件,并根据配置加载所有扩展类并缓存(不初始化)。
    2. 根据传入的名称初始化对应的扩展类。
    3. 尝试查找符合条件的包装类:包含扩展点的setter方法,例如setProtocol(Protocol protocol)方法会自动注入protocol扩展点实现;包含与扩展点类型相同的构造函数,为其注入扩展类实例,例如本次初始化一个Class A,初始化完成后,会寻找构造参数中需要Class A 的包装类,然后注入A实例,并初始化这个包装类。
    4. 返回对应的扩展类实例。

    getExtension方法的核心实现逻辑如下。

    public T getExtension(String name) {
        if (name == null || name.length() == 0)
            throw new IllegalArgumentException("Extension name == null");
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        //先从cachedInstances中取,cachedInstances是ConcurrentMap<String, Holder>类型,存储的是扩展名和扩展类实例的映射关系
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder<Object>());
            holder = cachedInstances.get(name);
        }
        Object instance = holder.get();
        //如果没有取到值,则调用createExtension方法创建扩展类实例
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
    

    cachedInstances为扩展名称和扩展类实例之间的缓存。当给定名称的扩展类实现缓存没有命中的时候,将调用createExtension来生成实例。

    private T createExtension(String name) {
        //获取扩展名称对应扩展点实现类的Class对象
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            //先根据Class对象查询EXTENSION_INSTANCES,能否查到class对象对应的实例。EXTENSION_INSTANCES存的的扩展点实现类和对应实例之间的关系。
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                //如果没有,就创建出class对象的实例,并存放到EXTENSION_INSTANCES静态变量中。
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            //向扩展类对象中注入其他依赖的属性,如扩展类A依赖了扩展类B
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            //遍历扩展点包装类,用于初始化包装类实例
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            //返回创建的实例
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                                            type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }
    

    首先获取到扩展点实现类的class对象,有了class对象,接下来就可以创建类了,所以这一步很关键:Class<?> clazz = getExtensionClasses().get(name);

    private Map<String, Class<?>> getExtensionClasses() {
        //cachedClass为扩展名称和扩展类类型之间映射关系的缓存。如果能取得到则返回,否则进行加载
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    //加载Classes
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
    

    cachedClass为扩展名称和扩展类类型之间映射关系的缓存。在缓存没有命中的情况下,需要执行loadExtensionClasses逻辑。

    // synchronized in getExtensionClasses
    private Map<String, Class<?>> loadExtensionClasses() {
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        //取SPI的默认值
        if (defaultAnnotation != null) {
            String value = defaultAnnotation.value();
            if ((value = value.trim()).length() > 0) {
                String[] names = NAME_SEPARATOR.split(value);
                if (names.length > 1) {
                    throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                                                    + ": " + Arrays.toString(names));
                }
                if (names.length == 1) cachedDefaultName = names[0];
            }
        }
        //调用loadDirectory方法从不同的目录分别寻找class配置,并把结果放入extensionClasses中返回
        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        loadDirectory(extensionClasses, DUBBO_DIRECTORY);
        loadDirectory(extensionClasses, SERVICES_DIRECTORY);
        return extensionClasses;
    }
    

    通过调用loadDirectory方法去取到扩展类名称和类型的对应关系。

    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
        //拼出配置文件的路径
        String fileName = dir + type.getName();
        try {
            Enumeration<java.net.URL> urls;
            ClassLoader classLoader = findClassLoader();
            //获取到所有匹配路径的扩展类配置文件的URL
            if (classLoader != null) {
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            if (urls != null) {
                //遍历每一个url加载扩展类配置文件
                while (urls.hasMoreElements()) {
                    java.net.URL resourceURL = urls.nextElement();
                    //调用loadResource读取扩展类配置文件
                    loadResource(extensionClasses, classLoader, resourceURL);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                         type + ", description file: " + fileName + ").", t);
        }
    }
    

    方法最终调用loadResource方法加载扩展类配置文件

    private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
            try {
                //一行一行读取扩展类配置文件
                String line;
                while ((line = reader.readLine()) != null) {
                    final int ci = line.indexOf('#');
                    if (ci >= 0) line = line.substring(0, ci);
                    line = line.trim();
                    if (line.length() > 0) {
                        try {
                            String name = null;
                            int i = line.indexOf('=');
                            if (i > 0) {
                                //获取配置文件的中key ,也就扩展类名称
                                name = line.substring(0, i).trim();
                                //配置文件中value,就是扩展类全类名
                                line = line.substring(i + 1).trim();
                            }
                            if (line.length() > 0) {
                                //调用loadClass方法加载类
                                loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
                            }
                        } catch (Throwable t) {
                            IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                            exceptions.put(line, e);
                        }
                    }
                }
            } finally {
                reader.close();
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                         type + ", class file: " + resourceURL + ") in " + resourceURL, t);
        }
    }
    

    在loadResource中读取文件的内容,一行行的进行解析,根据上面说过的配置规则,获取到对应的扩展名称和扩展类的完整路径。然后执行loadClass操作。loadClass的逻辑比较重要,下面来重点看一下。

    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
        //判断clazz是否是type的子类
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error when load extension class(interface: " +
                                            type + ", class line: " + clazz.getName() + "), class "
                                            + clazz.getName() + "is not subtype of interface.");
        }
        //clazz上是否有@Adaptive注解
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            //初始化cachedAdaptiveClass
            if (cachedAdaptiveClass == null) {
                cachedAdaptiveClass = clazz;
            } else if (!cachedAdaptiveClass.equals(clazz)) {
                //多个自适应类则抛出异常
                throw new IllegalStateException("More than 1 adaptive class found: "
                                                + cachedAdaptiveClass.getClass().getName()
                                                + ", " + clazz.getClass().getName());
            }
        } else if (isWrapperClass(clazz)) {
            //如果是包装扩展类则直接加入包装扩展类集合
            Set<Class<?>> wrappers = cachedWrapperClasses;
            if (wrappers == null) {
                cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                wrappers = cachedWrapperClasses;
            }
            wrappers.add(clazz);
        } else {
            clazz.getConstructor();
            if (name == null || name.length() == 0) {
                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 (names != null && names.length > 0) {
                Activate activate = clazz.getAnnotation(Activate.class);
                //如果有自动激活注解(@Activate),则缓存到自动激活的缓存中。
                if (activate != null) {
                    cachedActivates.put(names[0], activate);
                }
                //不是自适应类,不是包装类,剩下的就是普通扩展类,也会缓存起来。注意:自动激活也是普通扩展类的一种,只是会根据不同条件激活罢了。
                for (String n : names) {
                    if (!cachedNames.containsKey(clazz)) {
                        cachedNames.put(clazz, n);
                    }
                    Class<?> c = extensionClasses.get(n);
                    if (c == null) {
                        extensionClasses.put(n, clazz);
                    } else if (c != clazz) {
                        throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                    }
                }
            }
        }
    }
    
    private boolean isWrapperClass(Class<?> clazz) {
        try {
            clazz.getConstructor(type);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }
    

    至此整个获取Class对象的过程结束。注意此时仅仅是把Class加载到JVM中,但并没有做Class初始化。在加载Class文件是,会根据Class上的注解来判断扩展点类型,再根据类型分类做缓存。再回到private T createExtension(String name)方法,在获取到Class对象后先从EXTENSION_INSTANCES中获取到类对象实例,然后调用了injectExtension(instance);向实例中注入其他依赖属性:

    private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {
                for (Method method : instance.getClass().getMethods()) {
                    //找到set开头的方法。要求只有一个参数,并且是public方法
                    if (method.getName().startsWith("set")
                        && method.getParameterTypes().length == 1
                        && Modifier.isPublic(method.getModifiers())) {
                        /**
                             * Check {@link DisableInject} to see if we need auto injection for this property
                             */
                        if (method.getAnnotation(DisableInject.class) != null) {
                            continue;
                        }
                        Class<?> pt = method.getParameterTypes()[0];
                        try {
                            //获取到属性名称
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                            //通过ExtensionFactory获取实例
                            Object object = objectFactory.getExtension(pt, property);
                            if (object != null) {
                                //获取到了则调用set方法注入。
                                method.invoke(instance, object);
                            }
                        } catch (Exception e) {
                            logger.error("fail to inject via method " + method.getName()
                                         + " of interface " + type.getName() + ": " + e.getMessage(), e);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }
    

    在injectExtension方法中可以为类注入依赖的属性,它使用ExtensionFactory#getExtension(Class type, String name)来获取对应的bean实例,后面会讲到。

    injectExtension方法总体实现类似Spring的Ioc机制,原理也很简单:首先通过反射获取到所有方法,然后遍历以字符set开头的方法,得到set方法的参数类型,再通过ExtensionFactory寻找参数类型相同的扩展类实例,如果找到则设置进入。

    至此整个getExtension方法的实现逻辑的代码分析完毕。

    5、getAdaptiveExtension的实现原理

    getAdaptiveExtension相对独立,只有加载配置信息部分与getExtension共用了同一个方法。和获取普通扩展类一样,框架会先检查缓存中是否存在已经初始化好的Adaptive实例,没有则调用createAdaptiveExtension重新初始化化。初始化过程分为4步:

    1. 和getExtension一样先加载配置文件。
    2. 生成自适应类的代码字符串。
    3. 获取类加载器和编译器,并编译刚才生成的代码字符串。dubbo共有三种类型编译器实现。,后面会讲。
    4. 返回对应的自适应类实例。

    先来看一下getAdaptiveExtension方法:

    public T getAdaptiveExtension() {
        //先从cachedAdaptiveInstance缓存中获取自适应类对象。cachedAdaptiveInstance
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError == null) {
                synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get();
                    if (instance == null) {
                        try {
                            //执行createAdaptiveExtension方法创建自适应扩展实例。
                            instance = createAdaptiveExtension();
                            cachedAdaptiveInstance.set(instance);
                        } catch (Throwable t) {
                            createAdaptiveInstanceError = t;
                            throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
                        }
                    }
                }
            } else {
                throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
            }
        }
    
        return (T) instance;
    }
    

    上面说到了,对于同一种扩展来说,只能有一个扩展类添加@Adaptive注解。因此,首先去缓存中查找,缓存中不存在的话,则执行createAdaptiveExtension方法。

    private T createAdaptiveExtension() {
        try {
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
    

    injectExtension方法的逻辑上面已经分析过了,是执行依赖的注入过程。现在重点看一下getAdaptiveExtensionClass的逻辑,看看是如何生成Class对象的。

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

    首先调用getExtensionClasses加载,前面已经分析过,这里主要是加载到类上带有@Adaptive注解的类,如果存在,则会保存在cachedAdaptiveClass中,并且对于同一种扩展来说,只能有一个扩展类添加@Adaptive注解。可以看一下前面分析getExtension方法时的loadClass方法。如果没有加载到,则会调用createAdaptiveExtensionClass方法生成自适应Class:

    private Class<?> createAdaptiveExtensionClass() {
        //为扩展点接口自动生成实现类字符串
        String code = createAdaptiveExtensionClassCode();
        //获取ClassLoader
        ClassLoader classLoader = findClassLoader();
        //获取Dubbo编译器
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        //编译代码生成class对象。
        return compiler.compile(code, classLoader);
    }
    

    代码的自动生成处理的具体逻辑不再进行分析,概括起来,上面处理的事情主要有:

    1. 生成了包名。包名和传入的扩展类类型的包名一致。
    2. import了一条引用,为ExtensionLoader。其他的类在引用的时候都使用全路径。
    3. 生成class名称,名称的规则为扩展类类型名称+”$Adaptive”。
    4. 对于扩展类中的方法,生成包装。生成方法内容的逻辑比较复杂一些,后面会在另一篇文中另行分析。在添加@Adaptive注解的时候,如果没有传递value参数的话,则默认将扩展类的名称作为参数进行匹配。可以进行匹配的参数有多个。第一个参数匹配成功的话,则不再进行第二个参数的匹配。如果第一个参数没有匹配成功,则进行第二个参数的匹配,直到匹配@API注解的参数。

    6、getActiveExtension方法的实现原理

    getActivateExtension方法所有自动激活扩展点,它的三个参数分别为URL、URL指定的key所对应的值和group信息。key对应值有多个的话则使用逗号进行分隔。例如URL中为”https://localhost:20880/path?ext=name1,name2",则当key为"ext"的时候,则key所对应的值为"name1,name2"。

    需要注意的是,如果key对应的值中包含了”-default”的话,表示所有默认的@Activate类都不进行激活,只激活指定的。对于key对应的值包含了”-key”形式的话,则表示name为key的@Activate类也不进行激活。

    public List<T> getActivateExtension(URL url, String key, String group) {
        String value = url.getParameter(key);
        return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
    }
    
    public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> exts = new ArrayList<T>();
        List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
        if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
            //前面已经提到过了,先加载类,初始化所有扩展类实现的集合。
            getExtensionClasses();
            //加载完后遍历整个@Active注解集合,根据传入的URL匹配条件(匹配group,name等),得到所有符合激活条件的扩展类实现。然后根据@Avtivate中配置的before、after、order等参数进行排序。
            for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
                String name = entry.getKey();
                Activate activate = entry.getValue();
                if (isMatchGroup(group, activate.group())) {
                    if (!names.contains(name)
                        && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
                        && isActive(activate, url)) {
                        T ext = getExtension(name);
                        exts.add(ext);
                    }
                }
            }
            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }
        //遍历所有用户自定义的扩展类名称,根据用户URL配置的顺序,调整扩展点激活顺序(遵循用户在url中的配置顺序,如”https://localhost:20880/path?ext=name1,name2",则扩展点ext的激活顺序为name1、name2)
        List<T> usrs = new ArrayList<T>();
        for (int i = 0; i < names.size(); i++) {
            String name = names.get(i);
            if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
                && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
                if (Constants.DEFAULT_KEY.equals(name)) {
                    if (!usrs.isEmpty()) {
                        exts.addAll(0, usrs);
                        usrs.clear();
                    }
                } else {
                    T ext = getExtension(name);
                    usrs.add(ext);
                }
            }
        }
        //返回所有自动激活类集合。
        if (!usrs.isEmpty()) {
            exts.addAll(usrs);
        }
        return exts;
    }
    

    理解了前面getExtension的逻辑后,再看实现逻辑还是很简单的吧,到此分析完毕。

    7、ExtensionFactory的实现原理

    通过前面的介绍我们可以知道ExtensionLoader类是整个SPI的核心,但是ExtensionLoader类本事是通过ExtensionFactory创建的

    @SPI
    public interface ExtensionFactory {
    
        /**
         * Get extension.
         *
         * @param type object type.
         * @param name object name.
         * @return object instance.
         */
        <T> T getExtension(Class<T> type, String name);
    
    }
    

    有3个实现类SpiExtensionFactory、SpringExtensionFactory和AdaptiveExtensionFactory,在AdaptiveExtensionFactory上有@Adaptive注解。因此AdaptiveExtensionFactory会作为一开始的默认实现类

    7.1、AdaptiveExtensionFactory类

    @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>();
            for (String name : loader.getSupportedExtensions()) {
                list.add(loader.getExtension(name));
            }
            factories = Collections.unmodifiableList(list);
        }
    
        @Override
        public <T> T getExtension(Class<T> type, String name) {
            for (ExtensionFactory factory : factories) {
                T extension = factory.getExtension(type, name);
                if (extension != null) {
                    return extension;
                }
            }
            return null;
        }
    
    }
    

    主要看一下这个构造函数.,因为工厂列表也是通过SPI实现的,因此首先获取所有公差扩展点的加载器,关于ExtensionLoader.getExtensionLoader我们最开始的时候已经分析过,可以回头看一下。

    获取到工厂类的ExtensionLoader对象之后,接着遍历所有工厂名称,获取到对应的工厂实例,并保存到factories列表中。看一下getSupportedExtensions方法。

    public Set<String> getSupportedExtensions() {
        Map<String, Class<?>> clazzes = getExtensionClasses();
        return Collections.unmodifiableSet(new TreeSet<String>(clazzes.keySet()));
    }
    
    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
    

    这些方法前面都分析过,最后返回的我们配置的key。

    8、总结

    本篇文章对Dubbo SPI的源码进行分析,ExtensionLoader类是实现Dubbo SPI最核心的类,希望这篇文章对大家阅读代码理解代码有帮助。

  • 相关阅读:
    Poj 2017 Speed Limit(水题)
    Poj 1316 Self Numbers(水题)
    Poj 1017 Packets(贪心策略)
    Poj 1017 Packets(贪心策略)
    Poj 2662,2909 Goldbach's Conjecture (素数判定)
    Poj 2662,2909 Goldbach's Conjecture (素数判定)
    poj 2388 Who's in the Middle(快速排序求中位数)
    poj 2388 Who's in the Middle(快速排序求中位数)
    poj 2000 Gold Coins(水题)
    poj 2000 Gold Coins(水题)
  • 原文地址:https://www.cnblogs.com/ChenBingJie123/p/15414765.html
Copyright © 2011-2022 走看看