Dubbo-SPI application

  Dubbo's own implementation of SPI is used to obtain an object of an implementation class

  1. Why Dubbo designed a set of SPI

    1. The original JDK SPI does not support caching: Dubbo designed the cache object-cachedInstances is a new ConcurrentHashMap <String, Holder <Object >> ()

    2. The original JDK SPI does not support the default value: Dubbo design default value-@SPI ("dubbo") represents the default spi object

      For example, @SPI ("dubbo") of Protocol is DubboProtocol to get the default object through ExtensionLoader.getExtensionLoader (Protocol.class) .getDefaultExtension ()

    3. JDK should use the For loop to determine the object: getExtension designed by Dubbo is flexible and convenient, and dynamically obtains the spi object

      For example, ExtensionLoader.getExtensionLoader (Protocol.class) .getExtension (spi key) to extract the object

    4. The original JDK does not support AOP function: Dubbo design adds AOP function, in the cachedWrapperClasses, in the original class, XxxxFilterWrapper XxxxListenerWrapper is wrapped

      For example   ProtocolFilterWrapper

    5. The original JDK does not support IOC function: Dubbo design adds IOC, inject code through the constructor

      例如 wrapperClass.getConstructor(type).newInstance(instance) 

        First obtain the Class object of the adaptive extension point, and then obtain the instance through reflection, and hand over the power of object creation to the framework. This is the control inversion

  Second, the implementation path in Dubbo

    way:

      ExtensionLoader.getExtension(String name)

    Realize:

      getExtensionLoader (Class <T> type) new an ExtensionLoader, then cache it

      getAdaptiveExtension () Get an object of the extended decoration class. This class has a rule. If it does not have an @Adaptive annotation, it will dynamically create a proxy class. For example, Protocol $ Adaptive

      getExtension (String name) Get an object

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/";

    private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
    
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>(); // 缓存spi对象和Extension对象的映射

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

    // ============================== 

    private final Class <?> type; 

    private final ExtensionFactory objectFactory; 

    private final ConcurrentMap <Class <?>, String> cachedNames = new ConcurrentHashMap <Class <?>, String> (); // The mapping relationship between cache extension implementation class and name 
    
    private final Holder <Map <String, Class <? >>> cachedClasses = new Holder <Map <String, Class <? >>> (); // The input parameter of the cache loadFile method, extensionClasses stores the mapping of the extension implementation class name and Class object 

    private final Map <String, Activate> cachedActivates = new ConcurrentHashMap < String, Activate> (); // cache extension implementation class name and activation information mapping 

    private volatile Class <?> CachedAdaptiveClass = null; // cache @Adaptive extension implementation type 

    private final ConcurrentMap <String, Holder <Object >>cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();

    private String cachedDefaultName;

    private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();  // adaptive的缓存对象
    private volatile Throwable createAdaptiveInstanceError;

    private Set<Class<?>> cachedWrapperClasses; // 缓存扩展实现类中的wrapper包装类
    
    private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();
    
    private static <T> boolean withExtensionAnnotation(Class<T> type) {
        return type.isAnnotationPresent(SPI.class);
    }
.......
}

    

Three, code flow

  -->getExtensionLoader(Class<T> type)

    -->new ExtensionLoader<T>(type)

      -->ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension())

        -> getAdaptiveExtension () assign value to cachedAdaptiveInstance

          -->createAdaptiveExtension()

            -> injectExtension ((T) getAdaptiveExtensionClass (). newInstance ()) IOC and DI ideas are used here

              -->getAdaptiveExtensionClass

                -> getExtensionClasses () assign value to cachedClasses

                  -->loadExtensionClasses()

                    -> loadFile (Map <String, Class <? >> extensionClasses, String dir) The class path in the load file has stored the class into cachedAdaptiveClass, cachedWrapperClasses, cachedActivates, cachedNames

                -> createAdaptiveExtensionClass () automatically generates and compiles a dynamic adaptive proxy class

                  -> createAdaptiveExtensionClassCode () Generate the corresponding proxy class code

                  --> com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension()

                  -> compiler.compile (code, classLoader) Generate the corresponding class object

                    -> getExtension (String name) returns the extension with the specified name

                      -->createExtension(String name)

                        -> getExtensionClasses Get all corresponding class objects

                        -->injectExtension(instance)

              -> injectExtension (T instance) Enter the IOC inversion control mode to achieve dynamic injection

                -->objectFactory.getExtension(pt, property)

                  -->SpiExtensionFactory.getExtension(type,name)

                    -->ExtensionLoader.getExtensionLoader(type)

                    -->loader.getAdaptiveExtension()

                  -->SpringExtensionFactory.getExtension(type,name)

                    -->context.getBean(name)

 

 

Four, code analysis

  dubbo入口   com.alibaba.dubbo.container.Main

public class Main {

    public static final String CONTAINER_KEY = "dubbo.container";

    public static final String SHUTDOWN_HOOK_KEY = "dubbo.shutdown.hook";
    
    private static final Logger logger = LoggerFactory.getLogger(Main.class);

    private static final ExtensionLoader<Container> loader = ExtensionLoader.getExtensionLoader(Container.class);
    
    private static volatile boolean running = true;

    public static void main(String[] args) {
        try {
            if (args == null || args.length == 0) {
                String config = ConfigUtils.getProperty(CONTAINER_KEY, loader.getDefaultExtensionName());
                args = Constants.COMMA_SPLIT_PATTERN.split(config);
            }
            
            final List<Container> containers = new ArrayList<Container>();
            for (int i = 0; i < args.length; i ++) {
                containers.add(loader.getExtension(args[i]));
            }
            logger.info("Use container type(" + Arrays.toString(args) + ") to run dubbo serivce.");
            
            if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) {
	            Runtime.getRuntime().addShutdownHook(new Thread() {
	                public void run() {
	                    for (Container container : containers) {
	                        try {
	                            container.stop();
	                            logger.info("Dubbo " + container.getClass().getSimpleName() + " stopped!");
	                        } catch (Throwable t) {
	                            logger.error(t.getMessage(), t);
	                        }
	                        synchronized (Main.class) {
	                            running = false;
	                            Main.class.notify();
	                        }
	                    }
	                }
	            });
            }
            
            for (Container container : containers) {
                container.start(); // 启动容器方法
                logger.info("Dubbo " + container.getClass().getSimpleName() + " started!");
            }
            System.out.println(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date()) + " Dubbo service server started!");
        } catch (RuntimeException e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
            System.exit(1);
        }
        synchronized (Main.class) {
            while (running) {
                try {
                    Main.class.wait();
                } catch (Throwable e) {
                }
            }
        }
    }
    
}
Get the corresponding object from EXTENSION_LOADERS (store the correspondence between SPI object and ExtensionLoader)
 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!");
        }
        if(!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type(" + type + 
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }
        // 从缓存中获取该对象
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
       // Use putIfAbsent here to return if there is a value, and there is an alternative operation like putExtension_loaders.putIfAbsent (type, new ExtensionLoader <T> (type) ); loader = (ExtensionLoader <T>) EXTENSION_LOADERS.get (type); } return loader; }

  Does not exist in the cache, build ExtensionLoader object, build type + objectFactory object

  objectFactory It is to provide all objects for dubbo's IOC

private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
@Adaptive 
  annotation on the class: on behalf of manual coding implementation, Dubbo will not generate a proxy class for this class such as ExtensionFactory
  annotation on the method: Dubbo will implement proxy logic for this method such as Protocol $ Adaptive

Get the corresponding Adaptive object and put it in cachedAdaptiveInstance cache

public T getAdaptiveExtension() {
      // 获取 adaptive缓存对象 Object instance = cachedAdaptiveInstance.get(); if (instance == null) { if(createAdaptiveInstanceError == null) { synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null) { try {
                  // 没有创建adaptive对象 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; }

  Create an adaptive extension class newInstance 

private T createAdaptiveExtension() {
        try {
       // 获取该对象 实例化后注入extension return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e); } }

  Get details of adaptive extension points

private Class <?> getAdaptiveExtensionClass () {
         getExtensionClasses (); 
        if (cachedAdaptiveClass! = null) {// If the implementation class of the extension point is annotated with @Adaptive, then directly return the implementation class 
            return cachedAdaptiveClass; 
        } 
      // Otherwise create an adaptation Proxy class return cachedAdaptiveClass = createAdaptiveExtensionClass (); }
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
cachedClasses store the similar relationship between spring and com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
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;
	}

  

 

 

 Load the corresponding class

// 此方法已经getExtensionClasses方法同步过。
    private Map<String, Class<?>> loadExtensionClasses() {
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if(defaultAnnotation != null) {
            String value = defaultAnnotation.value();
            if(value != null && (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<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);  // 真正使用这一行
        loadFile(extensionClasses, DUBBO_DIRECTORY);
        loadFile(extensionClasses, SERVICES_DIRECTORY);
        return extensionClasses;
    }

 Load the configuration file information to get the corresponding className

private void loadFile (Map <String, Class <? >> extensionClasses, String dir) { 
      // Assemble relative paths like META-INF / dubbo / internal / com.alibaba.dubbo.rpc.Protocol String fileName = dir + type.getName ();
try { Enumeration <java.net.URL> urls; ClassLoader classLoader = findClassLoader (); if (classLoader! = null) {
                   // getResources () get project file urls = classLoader.getResources (fileName); } else {
            // Use the system's classLoader and then call getResource urls = ClassLoader.getSystemResources (fileName); } if (urls! = Null) { while (urls.hasMoreElements()) { java.net.URL url = urls.nextElement(); try {
              // 读取绝对路径对应文件内容 BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8")); try { String line = null;
                    // 一行行读 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) {
                            // 那对对应class Class<?> clazz = Class.forName(line, true, classLoader);
                             // Is the class or interface represented by the isAssignableFrom type object, and whether the class represented by clazz is its superclass or superinterface, whether it returns true, or false 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. "); }
                             // Determine whether Adaptive is added to the corresponding cacheAdaptiveClass cache if there are Adaptive annotations on the clazz class if (clazz.isAnnotationPresent(Adaptive.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 {
                                // no @Adaptive annotation try {
                                // match the corresponding construction parameters, only if the class has the target interface construction method into the cacheWarapperClasses cache similar to ProtocolFilterWarppeer and ProtocolListenerWarpper meet the conditions clazz.getConstructor (type); Set <Class <?> > wrappers = cachedWrapperClasses; if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet <Class <? >> (); wrappers = cachedWrapperClasses; } wrappers.add (clazz); } catch (NoSuchMethodException e) {
                                  // Other parameterless constructs enter cacheActivates and cacheNames cache 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 " + url); } } } String[] names = NAME_SEPARATOR.split(name); if (names != null && names.length > 0) { Activate activate = clazz.getAnnotation(Activate.class);
                                    // 有@Activate注解的进入cachedActivates缓存 if (activate != null) { cachedActivates.put(names[0], activate); }
                                    // Exclude the wrapper class and other classes into cacheNames 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()); } } } } } } } catch (Throwable t) { IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + url + ", cause: " + t.getMessage(), t); exceptions.put(line, e); } } } // end of while read lines } finally { reader.close(); } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", class file: " + url + ") in " + url, t); } } // end of while urls } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", description file: " + fileName + ").", t); } }
ProtocolListenerWrapper conforms to clazz.getConstructor (type); conditions

 

 

 

 Create the corresponding packaging class-automatically generate a dynamic adaptive class

private Class<?> createAdaptiveExtensionClass() {
        String code = createAdaptiveExtensionClassCode();
        ClassLoader classLoader = findClassLoader();
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

 Generate the code code corresponding to the proxy class

private String createAdaptiveExtensionClassCode() {
        StringBuilder codeBuidler = new StringBuilder();
        Method[] methods = type.getMethods();
        boolean hasAdaptiveAnnotation = false;
      // 判断所有的方法上有没有@Adaptive注解 for(Method m : methods) { if(m.isAnnotationPresent(Adaptive.class)) { hasAdaptiveAnnotation = true; break; } } // 完全没有Adaptive方法,则不需要生成Adaptive类 if(! hasAdaptiveAnnotation) throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!"); codeBuidler.append("package " + type.getPackage().getName() + ";"); codeBuidler.append("\nimport " + ExtensionLoader.class.getName() + ";"); codeBuidler.append("\npublic class " + type.getSimpleName() + "$Adpative" + " implements " + type.getCanonicalName() + " {"); 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; } } // 有类型为URL的参数 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); } // parameter has no URL type else { String attribMethod = null; // find the parameter URL attribute 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 adative 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()); code.append(s); s = String.format ("\ nif (arg% d.% s () == null) throw new IllegalArgumentException (\"% s argument% s () == null \ ");", urlTypeIndex, attribMethod, pts [ urlTypeIndex] .getName (), attribMethod); code.append (s); s = String.format ("% s url = arg% d.% s ();", URL.class.getName (), urlTypeIndex, attribMethod ); code.append (s); } String [] value = adaptiveAnnotation.value (); // If the Key is not set, the dot separation of the interface name of the extension point is used 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 = new String[] {sb.toString()}; } 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); } 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 = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);", type.getName(), ExtensionLoader.class.getSimpleName(), type.getName()); code.append(s); // return statement if (!rt.equals(void.class)) { code.append("\nreturn "); } s = String.format("extension.%s(", method.getName()); code.append(s); for (int i = 0; i < pts.length; i++) { if (i != 0) code.append(", "); code.append("arg").append(i); } code.append(");"); } codeBuidler.append("\npublic " + rt.getCanonicalName() + " " + method.getName() + "("); for (int i = 0; i < pts.length; i ++) { if (i > 0) { codeBuidler.append(", "); } codeBuidler.append(pts[i].getCanonicalName()); codeBuidler.append(" "); codeBuidler.append("arg" + i); } codeBuidler.append(")"); if (ets.length > 0) { codeBuidler.append(" throws "); for (int i = 0; i < ets.length; i ++) { if (i > 0) { codeBuidler.append(", "); } codeBuidler.append(pts[i].getCanonicalName()); } } codeBuidler.append(" {"); codeBuidler.append(code.toString()); codeBuidler.append("\n}"); } codeBuidler.append("\n}"); if (logger.isDebugEnabled()) { logger.debug(codeBuidler.toString()); } return codeBuidler.toString(); }

 The code code class generated by default-found that none of the @Adaptive annotations are implemented

public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
    public void destroy() {
        throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }

    public int getDefaultPort() {
        throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }

    public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker {
        if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
        com.alibaba.dubbo.common.URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }

    public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg1;
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
}
 Returns the extension class with the specified name
public T getExtension(String name) {
		if (name == null || name.length() == 0)
		    throw new IllegalArgumentException("Extension name == null");
		if ("true".equals(name)) {
		    return getDefaultExtension();
		}
		Holder<Object> holder = cachedInstances.get(name);
		if (holder == null) {
		    cachedInstances.putIfAbsent(name, new Holder<Object>());
		    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;
	}

 

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, (T) clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && wrapperClasses.size() > 0) {
                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);
        }
    }
injection
private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {
          // 提取所有方法 for (Method method : instance.getClass().getMethods()) {
            // 查询是否有set方法 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); if (object != null) { 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; }

  

 

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;
    }

  

 

 

Guess you like

Origin www.cnblogs.com/huan30/p/12723574.html