您好,登錄后才能下訂單哦!
如何理解dubbo的ExtensionLoader.getActivateExtension,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
dubbo-2.7.3/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
public class ExtensionLoader<T> { 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<T> 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<T> getActivateExtension(URL url, String[] values, String group) { List<T> exts = new ArrayList<>(); List<String> names = values == null ? new ArrayList<>(0) : Arrays.asList(values); if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) { getExtensionClasses(); for (Map.Entry<String, Object> 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<T> 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<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; } // synchronized in getExtensionClasses 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; } private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) { String fileName = dir + type; try { Enumeration<java.net.URL> 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<String, Class<?>> 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<String, Class<?>> 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 <code>Activate</code> * <p> * 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<Object> 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貌似一直為空
),然后合并返回
dubbo-common-2.7.3-sources.jar!/org/apache/dubbo/common/extension/support/ActivateComparator.java
public class ActivateComparator implements Comparator<Object> { public static final Comparator<Object> 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問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。