千家信息网

如何理解dubbo的ExtensionLoader.getActivateExtension

发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,如何理解dubbo的ExtensionLoader.getActivateExtension,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的
千家信息网最后更新 2025年02月01日如何理解dubbo的ExtensionLoader.getActivateExtension

如何理解dubbo的ExtensionLoader.getActivateExtension,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

主要研究一下dubbo的ExtensionLoader.getActivateExtension

ExtensionLoader.getActivateExtension

dubbo-2.7.3/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java

public class ExtensionLoader {    private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);    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/";    //......    /**     * This is equivalent to {@code getActivateExtension(url, url.getParameter(key).split(","), null)}     *     * @param url   url     * @param key   url parameter key which used to get extension point names     * @param group group     * @return extension list which are activated.     * @see #getActivateExtension(org.apache.dubbo.common.URL, String[], String)     */    public List getActivateExtension(URL url, String key, String group) {        String value = url.getParameter(key);        return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);    }    /**     * Get activate extensions.     *     * @param url    url     * @param values extension point names     * @param group  group     * @return extension list which are activated     * @see org.apache.dubbo.common.extension.Activate     */    public List getActivateExtension(URL url, String[] values, String group) {        List exts = new ArrayList<>();        List names = values == null ? new ArrayList<>(0) : Arrays.asList(values);        if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {            getExtensionClasses();            for (Map.Entry entry : cachedActivates.entrySet()) {                String name = entry.getKey();                Object activate = entry.getValue();                String[] activateGroup, activateValue;                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;                }                if (isMatchGroup(group, activateGroup)) {                    T ext = getExtension(name);                    if (!names.contains(name)                            && !names.contains(REMOVE_VALUE_PREFIX + name)                            && isActive(activateValue, url)) {                        exts.add(ext);                    }                }            }            exts.sort(ActivateComparator.COMPARATOR);        }        List usrs = new ArrayList<>();        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)) {                if (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;    }    private Map> getExtensionClasses() {        Map> classes = cachedClasses.get();        if (classes == null) {            synchronized (cachedClasses) {                classes = cachedClasses.get();                if (classes == null) {                    classes = loadExtensionClasses();                    cachedClasses.set(classes);                }            }        }        return classes;    }    // synchronized in getExtensionClasses    private Map> loadExtensionClasses() {        cacheDefaultExtensionName();        Map> 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;    }    private void loadDirectory(Map> extensionClasses, String dir, String type) {        String fileName = dir + type;        try {            Enumeration urls;            ClassLoader classLoader = findClassLoader();            if (classLoader != null) {                urls = classLoader.getResources(fileName);            } else {                urls = ClassLoader.getSystemResources(fileName);            }            if (urls != null) {                while (urls.hasMoreElements()) {                    java.net.URL resourceURL = urls.nextElement();                    loadResource(extensionClasses, classLoader, resourceURL);                }            }        } catch (Throwable t) {            logger.error("Exception occurred when loading extension class (interface: " +                    type + ", description file: " + fileName + ").", t);        }    }    private void loadResource(Map> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {        try {            try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {                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) {                                name = line.substring(0, i).trim();                                line = line.substring(i + 1).trim();                            }                            if (line.length() > 0) {                                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);                        }                    }                }            }        } catch (Throwable t) {            logger.error("Exception occurred when loading extension class (interface: " +                    type + ", class file: " + resourceURL + ") in " + resourceURL, t);        }    }    private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class clazz, String name) throws NoSuchMethodException {        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)) {            cacheAdaptiveClass(clazz);        } else if (isWrapperClass(clazz)) {            cacheWrapperClass(clazz);        } else {            clazz.getConstructor();            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)) {                cacheActivateClass(clazz, names[0]);                for (String n : names) {                    cacheName(clazz, n);                    saveInExtensionClass(extensionClasses, clazz, n);                }            }        }    }    /**     * cache Activate class which is annotated with Activate     * 

* for compatibility, also cache class with old alibaba Activate annotation */ private void cacheActivateClass(Class clazz, String name) { Activate activate = clazz.getAnnotation(Activate.class); if (activate != null) { cachedActivates.put(name, activate); } else { // support com.alibaba.dubbo.common.extension.Activate com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class); if (oldActivate != null) { cachedActivates.put(name, oldActivate); } } } /** * Find the extension with the given name. If the specified name is not found, then {@link IllegalStateException} * will be thrown. */ @SuppressWarnings("unchecked") public T getExtension(String name) { if (StringUtils.isEmpty(name)) { throw new IllegalArgumentException("Extension name == null"); } if ("true".equals(name)) { return getDefaultExtension(); } final Holder holder = getOrCreateHolder(name); Object instance = holder.get(); if (instance == null) { synchronized (holder) { instance = holder.get(); if (instance == null) { instance = createExtension(name); holder.set(instance); } } } return (T) instance; } //......}
  • getActivateExtension方法先执行getExtensionClasses加载extension类,这里主要通过loadDirectory方法加载META-INF/dubbo/、META-INF/dubbo/internal/、META-INF/services/三个目录下的extension

  • loadDirectory方法会调用loadResource方法,loadResource方法会调用loadClass方法,loadClass方法会通过cacheActivateClass把Activate注解信息放入到cachedActivates中

  • 之后遍历cachedActivates通过getExtension方法把extension实例放入exts,然后再根据ActivateComparator.COMPARATOR进行排序,最后加载usr的extension(目前看代码names貌似一直为空),然后合并返回

ActivateComparator

dubbo-common-2.7.3-sources.jar!/org/apache/dubbo/common/extension/support/ActivateComparator.java

public class ActivateComparator implements Comparator {    public static final Comparator COMPARATOR = new ActivateComparator();    @Override    public int compare(Object o1, Object o2) {        if (o1 == null && o2 == null) {            return 0;        }        if (o1 == null) {            return -1;        }        if (o2 == null) {            return 1;        }        if (o1.equals(o2)) {            return 0;        }        Class inf = findSpi(o1.getClass());        ActivateInfo a1 = parseActivate(o1.getClass());        ActivateInfo a2 = parseActivate(o2.getClass());        if ((a1.applicableToCompare() || a2.applicableToCompare()) && inf != null) {            ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(inf);            if (a1.applicableToCompare()) {                String n2 = extensionLoader.getExtensionName(o2.getClass());                if (a1.isLess(n2)) {                    return -1;                }                if (a1.isMore(n2)) {                    return 1;                }            }            if (a2.applicableToCompare()) {                String n1 = extensionLoader.getExtensionName(o1.getClass());                if (a2.isLess(n1)) {                    return 1;                }                if (a2.isMore(n1)) {                    return -1;                }            }        }        int n1 = a1 == null ? 0 : a1.order;        int n2 = a2 == null ? 0 : a2.order;        // never return 0 even if n1 equals n2, otherwise, o1 and o2 will override each other in collection like HashSet        return n1 > n2 ? 1 : -1;    }    private Class findSpi(Class clazz) {        if (clazz.getInterfaces().length <= 0) {            return null;        }        for (Class intf : clazz.getInterfaces()) {            if (intf.isAnnotationPresent(SPI.class)) {                return intf;            } else {                Class result = findSpi(intf);                if (result != null) {                    return result;                }            }        }        return null;    }    private ActivateInfo parseActivate(Class clazz) {        ActivateInfo info = new ActivateInfo();        if (clazz.isAnnotationPresent(Activate.class)) {            Activate activate = clazz.getAnnotation(Activate.class);            info.before = activate.before();            info.after = activate.after();            info.order = activate.order();        } else {            com.alibaba.dubbo.common.extension.Activate activate = clazz.getAnnotation(                    com.alibaba.dubbo.common.extension.Activate.class);            info.before = activate.before();            info.after = activate.after();            info.order = activate.order();        }        return info;    }    private static class ActivateInfo {        private String[] before;        private String[] after;        private int order;        private boolean applicableToCompare() {            return ArrayUtils.isNotEmpty(before) || ArrayUtils.isNotEmpty(after);        }        private boolean isLess(String name) {            return Arrays.asList(before).contains(name);        }        private boolean isMore(String name) {            return Arrays.asList(after).contains(name);        }    }}
  • ActivateComparator首先通过parseActivate解析注解信息到ActivateInfo,然后对于有配置before或after的则根据其值进行升序排序,否则则通过order(没有指定默认为0)来排序,大于返回1,否则返回-1

小结

  • getActivateExtension方法先执行getExtensionClasses加载extension类,这里主要通过loadDirectory方法加载META-INF/dubbo/、META-INF/dubbo/internal/、META-INF/services/三个目录下的extension

  • loadDirectory方法会调用loadResource方法,loadResource方法会调用loadClass方法,loadClass方法会通过cacheActivateClass把Activate注解信息放入到cachedActivates中

  • 之后遍历cachedActivates通过getExtension方法把extension实例放入exts,然后再根据ActivateComparator.COMPARATOR进行排序,最后加载usr的extension(目前看代码names貌似一直为空),然后合并返回

关于如何理解dubbo的ExtensionLoader.getActivateExtension问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。

0