dubbo中的ExtensionLoader详解

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License.You may obtain a copy of the License at * *http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.dubbo.common.extension; import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.common.extension.support.ActivateComparator; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ConcurrentHashSet; import com.alibaba.dubbo.common.utils.ConfigUtils; import com.alibaba.dubbo.common.utils.Holder; import com.alibaba.dubbo.common.utils.StringUtils; import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Pattern; /** * Load dubbo extensions *
    *
  • auto inject dependency extension
  • *
  • auto wrap extension in wrapper
  • *
  • default extension is an adaptive instance
  • *
* * @see Service Provider in Java 5 * @see com.alibaba.dubbo.common.extension.SPI * @see com.alibaba.dubbo.common.extension.Adaptive * @see com.alibaba.dubbo.common.extension.Activate */ 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/"; private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*"); //全局变量,缓存已经创建的ExtensionLoader[XXXX] private static final ConcurrentMap, ExtensionLoader> EXTENSION_LOADERS = new ConcurrentHashMap, ExtensionLoader>(); //{interface com.alibaba.dubbo.common.extension.ExtensionFactory=com.alibaba.dubbo.common.extension.ExtensionLoader[com.alibaba.dubbo.common.extension.ExtensionFactory], interface com.alibaba.dubbo.rpc.Protocol=com.alibaba.dubbo.common.extension.ExtensionLoader[com.alibaba.dubbo.rpc.Protocol]}//全局变量,缓存创建的ExtensionLoader[XXXX].type文件内的clazz实例对象 private static final ConcurrentMap, Object> EXTENSION_INSTANCES = new ConcurrentHashMap, Object>(); //{class com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory@916eb0, class com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory@10dbc7a}// ==============================/* * 构造器赋值,以该clazz作为名称的文件是要被加载的 */ private final Class type; /* * 构造器赋值 * 除了ExtensionLoader[ExtensionFactory]该属性是null,其他ExtensionLoader[XXXX]该属性是AdaptiveExtensionFactory * 该属性的功能是用来在injectExtension(T instance)进行ioc注入(通过setter注入) */ private final ExtensionFactory objectFactory; //AdaptiveExtensionFactory,该属性就是用于给创建的XXX$Adaptive注入属性/* * 缓存加载/META-INF/dubbo/internal/、/META-INF/dubbo/、/META-INF/services/目录下的ExtensionLoader.type文件内 * 未被@Adaptive注解且构造器的参数非ExtensionFactory.type,则把clazz=>name保存该属性。其中clazz和name就是ExtensionLoader.type文件内的配置, * 比如class SpringExtensionFactory=spring */ private final ConcurrentMap, String> cachedNames = new ConcurrentHashMap, String>(); /* * 缓存加载/META-INF/dubbo/internal/、/META-INF/dubbo/、/META-INF/services/目录下的ExtensionLoader.type文件内的 * 未被@Adaptive注解且构造器的参数非ExtensionFactory.type的clazz集合 */ private final Holder> cachedClasses = new Holder>(); //{registry=class com.alibaba.dubbo.registry.integration.RegistryProtocol, injvm=class com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol, dubbo=class com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol, mock=class com.alibaba.dubbo.rpc.support.MockProtocol}/* * 缓存加载/META-INF/dubbo/internal/、/META-INF/dubbo/、/META-INF/services/目录下的ExtensionLoader.type文件内 * 未被@Adaptive注解且clazz的构造器参数非ExtensionLoader.type的clazz(dubbo称为wrapper类)且clazz被@Activate注解的name和Activate.value */ private final Map cachedActivates = new ConcurrentHashMap(); //如果被加载的类被@Activate注解,则存放其name和Activate.value private final ConcurrentMap> cachedInstances = new ConcurrentHashMap>(); //{spring=com.alibaba.dubbo.common.utils.Holder@1282ed8, spi=com.alibaba.dubbo.common.utils.Holder@f57048} private final Holder cachedAdaptiveInstance = new Holder(); //value=https://www.it610.com/article/AdaptiveExtensionFactory/* * 缓存/META-INF/dubbo/internal/、/META-INF/dubbo/、/META-INF/services/目录下的ExtensionLoader.type文件内被@Adaptive注解的clazz, * ExtensionLoader.type文件内最多只能有一个被@Adaptive注解的clazz,超过一个则抛异常 */ private volatile Class cachedAdaptiveClass = null; //如果要加载的类被Adaptive注解,则赋值为该class。对于ExtensionFactory来说,其三个子类AdaptiveExtensionFactory、SpiExtensionFactory、SpringExtensionFactory只有AdaptiveExtensionFactory被注解了,因此就是AdaptiveExtensionFactory /* * 存放的是@SPI注解的value值,比如com.alibaba.dubbo.rpc.Protocol被@SPI("dubbo"),则该值就是dubbo * 在ExtensionLoader.loadExtensionClasses()赋值 */ private String cachedDefaultName; private volatile Throwable createAdaptiveInstanceError; /* * 缓存/META-INF/dubbo/internal/、/META-INF/dubbo/、/META-INF/services/目录下的ExtensionLoader.type文件内 * 未被@Adaptive注解且clazz的构造器参数是ExtensionLoader.type的clazz,就是包装类 */ private Set> cachedWrapperClasses; private Map exceptions = new ConcurrentHashMap(); private ExtensionLoader(Class type) { this.type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); //ExtensionLoader.getAdaptiveExtension(),AdaptiveExtensionFactory }private static boolean withExtensionAnnotation(Class type) { return type.isAnnotationPresent(SPI.class); }@SuppressWarnings("unchecked") public static ExtensionLoader getExtensionLoader(Class type) { if (type == null) throw new IllegalArgumentException("Extension type == null"); if (!type.isInterface()) { throw new IllegalArgumentException("Extension type(" + type + ") is not interface!"); } if (!withExtensionAnnotation(type)) { throw new IllegalArgumentException("Extension type(" + type + ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!"); }ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type); if (loader == null) { EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type)); loader = (ExtensionLoader) EXTENSION_LOADERS.get(type); } return loader; }private static ClassLoader findClassLoader() { return ExtensionLoader.class.getClassLoader(); }public String getExtensionName(T extensionInstance) { return getExtensionName(extensionInstance.getClass()); }public String getExtensionName(Class extensionClass) { return cachedNames.get(extensionClass); }/** * This is equivalent to {@code getActivateExtension(url, key, null)} * * @param url url * @param key url parameter key which used to get extension point names * @return extension list which are activated. * @see #getActivateExtension(com.alibaba.dubbo.common.URL, String, String) */ public List getActivateExtension(URL url, String key) { return getActivateExtension(url, key, null); }/** * This is equivalent to {@code getActivateExtension(url, values, null)} * * @param urlurl * @param values extension point names * @return extension list which are activated * @see #getActivateExtension(com.alibaba.dubbo.common.URL, String[], String) */ public List getActivateExtension(URL url, String[] values) { return getActivateExtension(url, values, null); }/** * This is equivalent to {@code getActivateExtension(url, url.getParameter(key).split(","), null)} * * @param urlurl * @param keyurl parameter key which used to get extension point names * @param group group * @return extension list which are activated. * @see #getActivateExtension(com.alibaba.dubbo.common.URL, String[], String) */ public List getActivateExtension(URL url, String key, String group) { String value = https://www.it610.com/article/url.getParameter(key); return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group); }/** * Get activate extensions. * * @param urlurl * @param values extension point names * @param groupgroup * @return extension list which are activated * @see com.alibaba.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(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { getExtensionClasses(); for (Map.Entry entry : cachedActivates.entrySet()) { String name = entry.getKey(); Activate activate = entry.getValue(); if (isMatchGroup(group, activate.group())) { T ext = getExtension(name); if (!names.contains(name) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name) && isActive(activate, url)) { exts.add(ext); } } } Collections.sort(exts, ActivateComparator.COMPARATOR); } List usrs = new ArrayList(); 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; }private boolean isMatchGroup(String group, String[] groups) { if (group == null || group.length() == 0) { return true; } if (groups != null && groups.length > 0) { for (String g : groups) { if (group.equals(g)) { return true; } } } return false; }private boolean isActive(Activate activate, URL url) { String[] keys = activate.value(); if (keys.length == 0) { return true; } for (String key : keys) { for (Map.Entry entry : url.getParameters().entrySet()) { String k = entry.getKey(); String v = entry.getValue(); if ((k.equals(key) || k.endsWith("." + key)) && ConfigUtils.isNotEmpty(v)) { return true; } } } return false; }/** * Get extension's instance. Return null if extension is not found or is not initialized. Pls. note * that this method will not trigger extension load. * * In order to trigger extension load, call {@link #getExtension(String)} instead. * * @see #getExtension(String) */ @SuppressWarnings("unchecked") public T getLoadedExtension(String name) { if (name == null || name.length() == 0) throw new IllegalArgumentException("Extension name == null"); Holder holder = cachedInstances.get(name); if (holder == null) { cachedInstances.putIfAbsent(name, new Holder()); holder = cachedInstances.get(name); } return (T) holder.get(); }/** * Return the list of extensions which are already loaded. * * Usually {@link #getSupportedExtensions()} should be called in order to get all extensions. * * @see #getSupportedExtensions() */ public Set getLoadedExtensions() { return Collections.unmodifiableSet(new TreeSet(cachedInstances.keySet())); }/** * Find the extension with the given name. If the specified name is not found, then {@link IllegalStateException} * will be thrown. */ /* * 在生成的自适应类内执行ExtensionLoader[XXXX].getExtension(String name) * 功能就是获取ExtensionLoader.type文件内name对应的clazz实例 */ @SuppressWarnings("unchecked") public T getExtension(String name) {//该方法功能就是获取ExtensionLoader.type文件内名称是name的对象实例,并放入缓存 if (name == null || name.length() == 0) throw new IllegalArgumentException("Extension name == null"); if ("true".equals(name)) { return getDefaultExtension(); } Holder holder = cachedInstances.get(name); if (holder == null) { cachedInstances.putIfAbsent(name, new Holder()); holder = cachedInstances.get(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; }/** * Return default extension, return null if it's not configured. */ public T getDefaultExtension() { getExtensionClasses(); if (null == cachedDefaultName || cachedDefaultName.length() == 0 || "true".equals(cachedDefaultName)) { return null; } return getExtension(cachedDefaultName); }public boolean hasExtension(String name) { if (name == null || name.length() == 0) throw new IllegalArgumentException("Extension name == null"); try { this.getExtensionClass(name); return true; } catch (Throwable t) { return false; } }public Set getSupportedExtensions() { Map> clazzes = getExtensionClasses(); //{spring=class com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory, spi=class com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory} return Collections.unmodifiableSet(new TreeSet(clazzes.keySet())); }/** * Return default extension name, return null if not configured. */ public String getDefaultExtensionName() { getExtensionClasses(); return cachedDefaultName; }/** * Register new extension via API * * @param nameextension name * @param clazz extension class * @throws IllegalStateException when extension with the same name has already been registered. */ public void addExtension(String name, Class clazz) { getExtensionClasses(); // load classesif (!type.isAssignableFrom(clazz)) { throw new IllegalStateException("Input type " + clazz + "not implement Extension " + type); } if (clazz.isInterface()) { throw new IllegalStateException("Input type " + clazz + "can not be interface!"); }if (!clazz.isAnnotationPresent(Adaptive.class)) { if (StringUtils.isBlank(name)) { throw new IllegalStateException("Extension name is blank (Extension " + type + ")!"); } if (cachedClasses.get().containsKey(name)) { throw new IllegalStateException("Extension name " + name + " already existed(Extension " + type + ")!"); }cachedNames.put(clazz, name); cachedClasses.get().put(name, clazz); } else { if (cachedAdaptiveClass != null) { throw new IllegalStateException("Adaptive Extension already existed(Extension " + type + ")!"); }cachedAdaptiveClass = clazz; } }/** * Replace the existing extension via API * * @param nameextension name * @param clazz extension class * @throws IllegalStateException when extension to be placed doesn't exist * @deprecated not recommended any longer, and use only when test */ @Deprecated public void replaceExtension(String name, Class clazz) { getExtensionClasses(); // load classesif (!type.isAssignableFrom(clazz)) { throw new IllegalStateException("Input type " + clazz + "not implement Extension " + type); } if (clazz.isInterface()) { throw new IllegalStateException("Input type " + clazz + "can not be interface!"); }if (!clazz.isAnnotationPresent(Adaptive.class)) { if (StringUtils.isBlank(name)) { throw new IllegalStateException("Extension name is blank (Extension " + type + ")!"); } if (!cachedClasses.get().containsKey(name)) { throw new IllegalStateException("Extension name " + name + " not existed(Extension " + type + ")!"); }cachedNames.put(clazz, name); cachedClasses.get().put(name, clazz); cachedInstances.remove(name); } else { if (cachedAdaptiveClass == null) { throw new IllegalStateException("Adaptive Extension not existed(Extension " + type + ")!"); }cachedAdaptiveClass = clazz; cachedAdaptiveInstance.set(null); } }@SuppressWarnings("unchecked") public T getAdaptiveExtension() { Object instance = cachedAdaptiveInstance.get(); if (instance == null) { if (createAdaptiveInstanceError == null) { synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null) { try { instance = createAdaptiveExtension(); //AdaptiveExtensionFactory, AdaptiveCompiler, com.alibaba.dubbo.rpc.Protocol$Adaptive@131a794 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; }private IllegalStateException findException(String name) { for (Map.Entry entry : exceptions.entrySet()) { if (entry.getKey().toLowerCase().contains(name.toLowerCase())) { return entry.getValue(); } } StringBuilder buf = new StringBuilder("No such extension " + type.getName() + " by name " + name); int i = 1; for (Map.Entry entry : exceptions.entrySet()) { if (i == 1) { buf.append(", possible causes: "); }buf.append("\r\n("); buf.append(i++); buf.append(") "); buf.append(entry.getKey()); buf.append(":\r\n"); buf.append(StringUtils.toString(entry.getValue())); } return new IllegalStateException(buf.toString()); }/* * */ @SuppressWarnings("unchecked") private T createExtension(String name) { Class clazz = getExtensionClasses().get(name); if (clazz == null) { throw findException(name); } try { T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } injectExtension(instance); Set> 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); } }//dubbo的ioc注入功能,通过setter注入 private T injectExtension(T instance) { try { if (objectFactory != null) { for (Method method : instance.getClass().getMethods()) { if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())) { Class pt = method.getParameterTypes()[0]; try { String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; Object object = objectFactory.getExtension(pt, property); //AdaptiveExtensionFactory.getExtension(Class, String) if (object != null) { //通过setter进行注入,即ioc注入 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; }private Class getExtensionClass(String name) { if (type == null) throw new IllegalArgumentException("Extension type == null"); if (name == null) throw new IllegalArgumentException("Extension name == null"); Class clazz = getExtensionClasses().get(name); if (clazz == null) throw new IllegalStateException("No such extension \"" + name + "\" for " + type.getName() + "!"); return clazz; }private Map> getExtensionClasses() { Map> classes = cachedClasses.get(); if (classes == null) { synchronized (cachedClasses) { classes = cachedClasses.get(); if (classes == null) { classes = loadExtensionClasses(); //{spring=class com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory, spi=class com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory}{zookeeper=class com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistryFactory, multicast=class com.alibaba.dubbo.registry.multicast.MulticastRegistryFactory} cachedClasses.set(classes); } } } return classes; }// synchronized in getExtensionClasses /* * 加载META-INF/dubbo/internal/、META-INF/dubbo/、META-INF/services/下的ExtensionLoader.type文件 * */ private Map> loadExtensionClasses() { final SPI defaultAnnotation = type.getAnnotation(SPI.class); if (defaultAnnotation != null) { String value = https://www.it610.com/article/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]; } }Map> extensionClasses = new HashMap>(); loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY); //META-INF/dubbo/internal/ loadDirectory(extensionClasses, DUBBO_DIRECTORY); //META-INF/dubbo/ loadDirectory(extensionClasses, SERVICES_DIRECTORY); //META-INF/services/ return extensionClasses; }private void loadDirectory(Map> extensionClasses, String dir) { String fileName = dir + type.getName(); //META-INF/dubbo/internal/com.alibaba.dubbo.registry.RegistryFactory 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 when load extension class(interface: " + type + ", description file: " + fileName + ").", t); } }private void loadResource(Map> 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) { 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); } } } } finally { reader.close(); } } catch (Throwable t) { logger.error("Exception when load 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 when load extension class(interface: " + type + ", class line: " + clazz.getName() + "), class " + clazz.getName() + "is not subtype of interface."); } if (clazz.isAnnotationPresent(Adaptive.class)) {//如果要被加载的类被@Adaptive注解,则把ExtensionLoader.cachedAdaptiveClass赋值为该class 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)) {//如果要被加载的类的构造器的参数是ExtensionLoader.type则返回true,否则返回false Set> wrappers = cachedWrapperClasses; if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet>(); wrappers = cachedWrapperClasses; } wrappers.add(clazz); } else { clazz.getConstructor(); if (name == null || name.length() == 0) { name = findAnnotationName(clazz); if (name == null || name.length() == 0) { if (clazz.getSimpleName().length() > type.getSimpleName().length() && clazz.getSimpleName().endsWith(type.getSimpleName())) { name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase(); } else { 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); 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; } }@SuppressWarnings("deprecation") private String findAnnotationName(Class clazz) { com.alibaba.dubbo.common.Extension extension = clazz.getAnnotation(com.alibaba.dubbo.common.Extension.class); if (extension == null) { String name = clazz.getSimpleName(); if (name.endsWith(type.getSimpleName())) { name = name.substring(0, name.length() - type.getSimpleName().length()); } return name.toLowerCase(); } return extension.value(); }/* * 创建自适应扩展并注入属性 */ @SuppressWarnings("unchecked") private T createAdaptiveExtension() { try { return injectExtension((T) getAdaptiveExtensionClass().newInstance()); //com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory } catch (Exception e) { throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e); } }/* * 获取自适应clazz */ private Class getAdaptiveExtensionClass() { getExtensionClasses(); //如果缓存不存在则先加载 if (cachedAdaptiveClass != null) {//说明ExtensionFactory.type文件内的clazz有被@Adaptive注解的类 return cachedAdaptiveClass; } return cachedAdaptiveClass = createAdaptiveExtensionClass(); }private Class createAdaptiveExtensionClass() { String code = createAdaptiveExtensionClassCode(); //生成的是Protocol$Adaptive这个java文件内容 ClassLoader classLoader = findClassLoader(); com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); //AdaptiveCompiler return compiler.compile(code, classLoader); }/* * 创建自适应的clazz是内容 * 生成的代码功能就是执行 * ExtensionLoader[XXXX].getExtension(String name) */ private String createAdaptiveExtensionClassCode() { StringBuilder codeBuilder = new StringBuilder(); Method[] methods = type.getMethods(); boolean hasAdaptiveAnnotation = false; for (Method m : methods) { if (m.isAnnotationPresent(Adaptive.class)) { hasAdaptiveAnnotation = true; break; } } // no need to generate adaptive class since there's no adaptive method found. if (!hasAdaptiveAnnotation) throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!"); codeBuilder.append("package ").append(type.getPackage().getName()).append("; "); //package com.alibaba.dubbo.rpc; codeBuilder.append("\nimport ").append(ExtensionLoader.class.getName()).append("; "); //import com.alibaba.dubbo.common.extension.ExtensionLoader; codeBuilder.append("\npublic class ").append(type.getSimpleName()).append("$Adaptive").append(" implements ").append(type.getCanonicalName()).append(" {"); //public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol { for (Method method : methods) { Class rt = method.getReturnType(); Class[] pts = method.getParameterTypes(); Class[] ets = method.getExceptionTypes(); Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class); StringBuilder code = new StringBuilder(512); if (adaptiveAnnotation == null) { code.append("throw new UnsupportedOperationException(\"method ") .append(method.toString()).append(" of interface ") .append(type.getName()).append(" is not adaptive method!\"); "); } else { int urlTypeIndex = -1; for (int i = 0; i < pts.length; ++i) { if (pts[i].equals(URL.class)) { urlTypeIndex = i; break; } } // found parameter in URL type if (urlTypeIndex != -1) { // Null Point check String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"url == null\"); ", urlTypeIndex); code.append(s); s = String.format("\n%s url = arg%d; ", URL.class.getName(), urlTypeIndex); code.append(s); } // did not find parameter in URL type else { String attribMethod = null; // find URL getter method LBL_PTS: for (int i = 0; i < pts.length; ++i) { Method[] ms = pts[i].getMethods(); for (Method m : ms) { String name = m.getName(); if ((name.startsWith("get") || name.length() > 3) && Modifier.isPublic(m.getModifiers()) && !Modifier.isStatic(m.getModifiers()) && m.getParameterTypes().length == 0 && m.getReturnType() == URL.class) { urlTypeIndex = i; attribMethod = name; break LBL_PTS; } } } if (attribMethod == null) { throw new IllegalStateException("fail to create adaptive class for interface " + type.getName() + ": not found url parameter or url attribute in parameters of method " + method.getName()); }// Null point check String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\"); ", urlTypeIndex, pts[urlTypeIndex].getName()); //if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null"); code.append(s); s = String.format("\nif (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\"); ", urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod); //if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null"); code.append(s); s = String.format("%s url = arg%d.%s(); ", URL.class.getName(), urlTypeIndex, attribMethod); //com.alibaba.dubbo.common.URL url = arg0.getUrl(); code.append(s); }String[] value = https://www.it610.com/article/adaptiveAnnotation.value(); // value is not set, use the value generated from class name as the key if (value.length == 0) { char[] charArray = type.getSimpleName().toCharArray(); StringBuilder sb = new StringBuilder(128); for (int i = 0; i < charArray.length; i++) { if (Character.isUpperCase(charArray[i])) { if (i != 0) { sb.append("."); } sb.append(Character.toLowerCase(charArray[i])); } else { sb.append(charArray[i]); } } value = https://www.it610.com/article/new String[]{sb.toString()}; //[protocol] }boolean hasInvocation = false; for (int i = 0; i < pts.length; ++i) { if (pts[i].getName().equals("com.alibaba.dubbo.rpc.Invocation")) { // Null Point check String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"invocation == null\"); ", i); code.append(s); s = String.format("\nString methodName = arg%d.getMethodName(); ", i); code.append(s); hasInvocation = true; break; } }String defaultExtName = cachedDefaultName; String getNameCode = null; for (int i = value.length - 1; i >= 0; --i) { if (i == value.length - 1) { if (null != defaultExtName) { if (!"protocol".equals(value[i])) if (hasInvocation) getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName); else getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName); else getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName); //( url.getProtocol() == null ? "dubbo" : url.getProtocol() ) } else { if (!"protocol".equals(value[i])) if (hasInvocation) getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName); else getNameCode = String.format("url.getParameter(\"%s\")", value[i]); else getNameCode = "url.getProtocol()"; } } else { if (!"protocol".equals(value[i])) if (hasInvocation) getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName); else getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode); else getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode); } } code.append("\nString extName = ").append(getNameCode).append("; "); // check extName == null? String s = String.format("\nif(extName == null) " + "throw new IllegalStateException(\"Fail to get extension(%s) name from url(\" + url.toString() + \") use keys(%s)\"); ", type.getName(), Arrays.toString(value)); code.append(s); s = String.format("\n%s extension = (% 0) { codeBuilder.append(", "); } codeBuilder.append(pts[i].getCanonicalName()); codeBuilder.append(" "); codeBuilder.append("arg").append(i); } codeBuilder.append(")"); if (ets.length > 0) { codeBuilder.append(" throws "); for (int i = 0; i < ets.length; i++) { if (i > 0) { codeBuilder.append(", "); } codeBuilder.append(ets[i].getCanonicalName()); } } codeBuilder.append(" {"); codeBuilder.append(code.toString()); codeBuilder.append("\n}"); } codeBuilder.append("\n}"); if (logger.isDebugEnabled()) { logger.debug(codeBuilder.toString()); } return codeBuilder.toString(); }@Override public String toString() { return this.getClass().getName() + "[" + type.getName() + "]"; }}
【dubbo中的ExtensionLoader详解】

    推荐阅读