zoukankan      html  css  js  c++  java
  • 2.2 dubbo-spi源码解析

     1 package com.alibaba.dubbo.demo.test;
     2 
     3 import com.alibaba.dubbo.common.extension.ExtensionLoader;
     4 import com.alibaba.dubbo.rpc.Protocol;
     5 
     6 public class TestExtension {
     7     public static void main(String[] args) {
     8         ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);
     9         final Protocol dubboProtocol = loader.getExtension("dubbo");
    10         final Protocol adaptiveExtension = loader.getAdaptiveExtension();
    11     }
    12 }

    讲解这三行代码的源码。

    一  Protocol接口的定义

     1 package com.alibaba.dubbo.rpc;
     2 
     3 import com.alibaba.dubbo.common.URL;
     4 import com.alibaba.dubbo.common.extension.Adaptive;
     5 import com.alibaba.dubbo.common.extension.SPI;
     6 
     7 /**
     8  * Protocol. (API/SPI, Singleton, ThreadSafe)
     9  */
    10 @SPI("dubbo")
    11 public interface Protocol {
    12 
    13     /**
    14      * 获取缺省端口,当用户没有配置端口时使用。
    15      *
    16      * @return 缺省端口
    17      */
    18     int getDefaultPort();
    19 
    20     /**
    21      * 暴露远程服务:<br>
    22      * 1. 协议在接收请求时,应记录请求来源方地址信息:RpcContext.getContext().setRemoteAddress();<br>
    23      * 2. export()必须是幂等的,也就是暴露同一个URL的Invoker两次,和暴露一次没有区别。<br>
    24      * 3. export()传入的Invoker由框架实现并传入,协议不需要关心。<br>
    25      *
    26      * @param <T>     服务的类型
    27      * @param invoker 服务的执行体
    28      * @return exporter 暴露服务的引用,用于取消暴露
    29      * @throws RpcException 当暴露服务出错时抛出,比如端口已占用
    30      */
    31     @Adaptive
    32     <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
    33 
    34     /**
    35      * 引用远程服务:<br>
    36      * 1. 当用户调用refer()所返回的Invoker对象的invoke()方法时,协议需相应执行同URL远端export()传入的Invoker对象的invoke()方法。<br>
    37      * 2. refer()返回的Invoker由协议实现,协议通常需要在此Invoker中发送远程请求。<br>
    38      * 3. 当url中有设置check=false时,连接失败不能抛出异常,并内部自动恢复。<br>
    39      *
    40      * @param <T>  服务的类型
    41      * @param type 服务的类型
    42      * @param url  远程服务的URL地址
    43      * @return invoker 服务的本地代理
    44      * @throws RpcException 当连接服务提供方失败时抛出
    45      */
    46     @Adaptive
    47     <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
    48 
    49     /**
    50      * 释放协议:<br>
    51      * 1. 取消该协议所有已经暴露和引用的服务。<br>
    52      * 2. 释放协议所占用的所有资源,比如连接和端口。<br>
    53      * 3. 协议在释放后,依然能暴露和引用新的服务。<br>
    54      */
    55     void destroy();
    56 }

    注意:这里有两个核心注解

    • @SPI:指定一个接口为SPI接口(可扩展接口)
      1 @Documented
      2 @Retention(RetentionPolicy.RUNTIME)
      3 @Target({ElementType.TYPE})
      4 public @interface SPI {
      5     /** 缺省扩展点名 */
      6     String value() default "";
      7 }
    • @Adaptive该注解可以注解在两个地方:

      • 接口上:例如AdaptiveExtensionFactory(该类不是工厂类,有特殊的逻辑)  AdaptiveCompiler(实际上也是工厂类,但是不能靠动态生成,否则会形成死循环)
      • 接口的方法上:会动态生成相应的动态类(实际上是一个工厂类,工厂设计模式),例如Protocol$Adapter

    这个接口极其重要,后续的整个服务暴露和服务调用会用到该接口的两个方法。

    二 获取ExtensionLoader

    1 ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);

    ExtensionLoader可以类比为JDK-SPI中的ServiceLoader

    首先来看一下ExtensionLoader的类属性:

     1     /** 存放SPI文件的三个目录,其中META-INF/services/也是jdk的SPI文件的存放目录 */
     2     private static final String SERVICES_DIRECTORY = "META-INF/services/";
     3     private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
     4     private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";//这个是最终jar包中存放spi文件的位置
     5 
     6     private static final Pattern NAME_SEPARATOR = Pattern.compile("\s*[,]+\s*");
     7     /** key: SPI接口Class value: 该接口的ExtensionLoader */
     8     private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
     9     /** key: SPI接口Class value: SPI实现类的对象实例 */
    10     private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();

    注意:上述的都是类属性,即所有该类的实例都共享。而后边的实例属性就属于每一个类的实例私有

    再来看一下ExtensionLoader的实例属性:

     1     /** SPI接口Class */
     2     private final Class<?> type;
     3     /** SPI实现类对象实例的创建工厂 */
     4     private final ExtensionFactory objectFactory;
     5     /** key: ExtensionClass的Class value: SPI实现类的key */
     6     private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();
     7     /** 存放所有的extensionClass */
     8     private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
     9 
    10     private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
    11     /** 缓存创建好的extensionClass实例 */
    12     private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
    13     /** 缓存创建好的适配类实例 */
    14     private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
    15     /** 存储类上带有@Adaptive注解的Class */
    16     private volatile Class<?> cachedAdaptiveClass = null;
    17     /** 默认的SPI文件中的key */
    18     private String cachedDefaultName;
    19     /** 存储在创建适配类实例这个过程中发生的错误 */
    20     private volatile Throwable createAdaptiveInstanceError;
    21     /** 存放具有一个type入参的构造器的实现类的Class对象 */
    22     private Set<Class<?>> cachedWrapperClasses;
    23     /** key :实现类的全类名  value: exception, 防止真正的异常被吞掉 */
    24     private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();

    来看一下getExtensionLoader(Class<T> type)的源码:

     1     /**
     2      * 1 校验入参type:非空 + 接口 + 含有@SPI注解
     3      * 2 根据type接口从全局缓存EXTENSION_LOADERS中获取ExtensionLoader,如果有直接返回;如果没有,则先创建,之后放入缓存,最后返回
     4      */
     5     public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
     6         if (type == null)
     7             throw new IllegalArgumentException("Extension type == null");
     8         if (!type.isInterface()) {
     9             throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
    10         }
    11         if (!withExtensionAnnotation(type)) {
    12             throw new IllegalArgumentException("Extension type(" + type +
    13                     ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
    14         }
    15 
    16         ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    17         if (loader == null) {
    18             EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
    19             loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    20         }
    21         return loader;
    22     }

    创建ExtensionLoader:

    1     private ExtensionLoader(Class<?> type) {
    2         this.type = type;
    3         objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    4     }

    当前创建的ExtensionLoader对象(我们取名为ExtensionLoader对象1)的type是com.alibaba.dubbo.rpc.Protocol,所以此时会执行:ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()。

    首先是创建ExtensionFactory,通过上边核心类部分ExtensionFactory接口的源码可以看出,此类也是一个SPI接口类,且没有指定默认的实现类的key。

    1 ExtensionLoader.getExtensionLoader(ExtensionFactory.class)

    下面的代码与上述的过程相似,只是此时创建的另外一个ExtensionLoader对象(我们取名为ExtensionLoader对象2)的type是com.alibaba.dubbo.common.extension.ExtensionFactory,而objectFactory是null。之后,这个ExtensionLoader对象2被放入EXTENSION_LOADERS缓存。这里给出ExtensionFactory的定义,该类也极其重要。//TODO

    1 package com.alibaba.dubbo.common.extension;
    2 
    3 @SPI
    4 public interface ExtensionFactory {
    5     <T> T getExtension(Class<T> type, String name);
    6 }

    之后执行ExtensionLoader对象2的getAdaptiveExtension()方法。

     1     /**
     2      * 首先从cachedAdaptiveInstance缓存中获取AdaptiveExtension实例
     3      * 如果不为null, 直接返回;
     4      * 如果为null, 先创建AdaptiveExtension实例, 之后放入cachedAdaptiveInstance缓存中,最后返回
     5      */
     6     public T getAdaptiveExtension() {
     7         Object instance = cachedAdaptiveInstance.get();
     8         if (instance == null) {
     9             if (createAdaptiveInstanceError == null) {
    10                 synchronized (cachedAdaptiveInstance) {
    11                     instance = cachedAdaptiveInstance.get();
    12                     if (instance == null) {
    13                         try {
    14                             instance = createAdaptiveExtension();
    15                             cachedAdaptiveInstance.set(instance);
    16                         } catch (Throwable t) {
    17                             createAdaptiveInstanceError = t;
    18                             throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
    19                         }
    20                     }
    21                 }
    22             } else {
    23                 throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
    24             }
    25         }
    26 
    27         return (T) instance;
    28     }

    来看createAdaptiveExtension()创建AdaptiveExtension的源码:

     1     /**
     2      * createAdaptiveExtension()
     3      * --getAdaptiveExtensionClass()
     4      *   //从dubbo-spi配置文件中获取AdaptiveExtensionClass
     5      *   --getExtensionClasses()
     6      *     --loadExtensionClasses()
     7      *       --loadFile(Map<String, Class<?>> extensionClasses, String dir)
     8      *   //创建动态代理类
     9      *   --createAdaptiveExtensionClass()
    10      *
    11      * --injectExtension(T instance)  //dubbo-ioc
    12      */
    13     private T createAdaptiveExtension() {
    14         try {
    15             return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    16         } catch (Exception e) {
    17             throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
    18         }
    19     }

    调用层级看注释。injectExtension(T instance)方法只对objectFactory有用,如果objectFactory==null,则直接返回T instance。所以这里返回的是getAdaptiveExtensionClass().newInstance()

    来看getAdaptiveExtensionClass()的源码:

     1     /**
     2      * 获取ExtensionClasses和适配类
     3      * 如果实现类上带有@Adaptive注解,直接创建修饰类
     4      * 如果方法上带有@Adaptive注解,动态生成代理类
     5      */
     6     private Class<?> getAdaptiveExtensionClass() {
     7         getExtensionClasses();
     8         if (cachedAdaptiveClass != null) {
     9             return cachedAdaptiveClass;
    10         }
    11         return cachedAdaptiveClass = createAdaptiveExtensionClass();
    12     }

    现在来看getExtensionClasses():

     1     /**
     2      * 先从cachedClasses缓存中获取所有的ExtensionClass,如果有,直接返回;
     3      * 如果没有,通过loadExtensionClasses()从SPI文件中去读取,之后写入缓存
     4      */
     5     private Map<String, Class<?>> getExtensionClasses() {
     6         Map<String, Class<?>> classes = cachedClasses.get();
     7         if (classes == null) {
     8             synchronized (cachedClasses) {
     9                 classes = cachedClasses.get();
    10                 if (classes == null) {
    11                     classes = loadExtensionClasses();
    12                     cachedClasses.set(classes);
    13                 }
    14             }
    15         }
    16         return classes;
    17     }

    现在来看loadExtensionClasses()

     1     /**
     2      * 1 从@SPI注解中将默认值解析出来,并缓存到cachedDefaultName中
     3      * 2 从SPI文件中获取extensionClass并存储到extensionClasses中,最后返回extensionClasses
     4      * 注意:此方法已经getExtensionClasses方法同步过。
     5      */
     6     private Map<String, Class<?>> loadExtensionClasses() {
     7         final SPI defaultAnnotation = type.getAnnotation(SPI.class);
     8         if (defaultAnnotation != null) {
     9             String value = defaultAnnotation.value();
    10             if (value != null && (value = value.trim()).length() > 0) {
    11                 String[] names = NAME_SEPARATOR.split(value);
    12                 if (names.length > 1) {
    13                     throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
    14                             + ": " + Arrays.toString(names));
    15                 }
    16                 if (names.length == 1) cachedDefaultName = names[0];
    17             }
    18         }
    19 
    20         Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
    21         loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    22         loadFile(extensionClasses, DUBBO_DIRECTORY);
    23         loadFile(extensionClasses, SERVICES_DIRECTORY);
    24         return extensionClasses;
    25     }

    之后来看一下非常重要的一个方法loadFile(Map<String, Class<?>> extensionClasses, String dir)。

      1     /**
      2      * 1 加载dir目录下的指定type名称的文件(例如:dubbo-2.5.5.jar中的/META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory)
      3      * 2 遍历该文件中的每一行
      4      * (1)获取实现类key和value, 例如 name=spi, line=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
      5      * (2)根据line创建Class对象
      6      * (3)将具有@Adaptive注解的实现类的Class对象放在cachedAdaptiveClass缓存中, 注意该缓存只能存放一个具有@Adaptive注解的实现类的Class对象,如果有两个满足条件,则抛异常
      7      * 下面的都是对不含@Adaptive注解的实现类的Class对象:
      8      * (4)查看是否具有含有一个type入参的构造器, 如果有(就是wrapper类), 将当前的Class对象放置到cachedWrapperClasses缓存中
      9      * (5)如果没有含有一个type入参的构造器, 获取无参构造器. 如果Class对象具有@Active注解, 将该对象以<实现类的key, active>存储起来
     10      * (6)最后,将<Class对象, 实现类的key>存入cachedNames缓存,并将这些Class存入extensionClasses中.
     11      * @param extensionClasses
     12      * @param dir
     13      */
     14     private void loadFile(Map<String, Class<?>> extensionClasses, String dir) {
     15         String fileName = dir + type.getName();
     16         try {
     17             Enumeration<java.net.URL> urls;
     18             ClassLoader classLoader = findClassLoader();
     19             if (classLoader != null) {
     20                 urls = classLoader.getResources(fileName);
     21             } else {
     22                 urls = ClassLoader.getSystemResources(fileName);
     23             }
     24             if (urls != null) {
     25                 while (urls.hasMoreElements()) {
     26                     java.net.URL url = urls.nextElement();
     27                     try {
     28                         BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
     29                         try {
     30                             String line = null;
     31                             while ((line = reader.readLine()) != null) {
     32                                 final int ci = line.indexOf('#');
     33                                 if (ci >= 0) line = line.substring(0, ci);
     34                                 line = line.trim();
     35                                 if (line.length() > 0) {
     36                                     try {
     37                                         String name = null;
     38                                         int i = line.indexOf('=');
     39                                         if (i > 0) {
     40                                             name = line.substring(0, i).trim();
     41                                             line = line.substring(i + 1).trim();
     42                                         }
     43                                         if (line.length() > 0) {
     44                                             Class<?> clazz = Class.forName(line, true, classLoader);
     45                                             if (!type.isAssignableFrom(clazz)) {
     46                                                 throw new IllegalStateException("Error when load extension class(interface: " +
     47                                                         type + ", class line: " + clazz.getName() + "), class "
     48                                                         + clazz.getName() + "is not subtype of interface.");
     49                                             }
     50                                             if (clazz.isAnnotationPresent(Adaptive.class)) {
     51                                                 if (cachedAdaptiveClass == null) {
     52                                                     cachedAdaptiveClass = clazz;
     53                                                 } else if (!cachedAdaptiveClass.equals(clazz)) {
     54                                                     throw new IllegalStateException("More than 1 adaptive class found: "
     55                                                             + cachedAdaptiveClass.getClass().getName()
     56                                                             + ", " + clazz.getClass().getName());
     57                                                 }
     58                                             } else {
     59                                                 try {
     60                                                     clazz.getConstructor(type);
     61                                                     Set<Class<?>> wrappers = cachedWrapperClasses;
     62                                                     if (wrappers == null) {
     63                                                         cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
     64                                                         wrappers = cachedWrapperClasses;
     65                                                     }
     66                                                     wrappers.add(clazz);
     67                                                 } catch (NoSuchMethodException e) {
     68                                                     clazz.getConstructor();
     69                                                     if (name == null || name.length() == 0) {
     70                                                         name = findAnnotationName(clazz);
     71                                                         if (name == null || name.length() == 0) {
     72                                                             if (clazz.getSimpleName().length() > type.getSimpleName().length()
     73                                                                     && clazz.getSimpleName().endsWith(type.getSimpleName())) {
     74                                                                 name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
     75                                                             } else {
     76                                                                 throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + url);
     77                                                             }
     78                                                         }
     79                                                     }
     80                                                     String[] names = NAME_SEPARATOR.split(name);
     81                                                     if (names != null && names.length > 0) {
     82                                                         Activate activate = clazz.getAnnotation(Activate.class);
     83                                                         if (activate != null) {
     84                                                             cachedActivates.put(names[0], activate);
     85                                                         }
     86                                                         for (String n : names) {
     87                                                             if (!cachedNames.containsKey(clazz)) {
     88                                                                 cachedNames.put(clazz, n);
     89                                                             }
     90                                                             Class<?> c = extensionClasses.get(n);
     91                                                             if (c == null) {
     92                                                                 extensionClasses.put(n, clazz);
     93                                                             } else if (c != clazz) {
     94                                                                 throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
     95                                                             }
     96                                                         }
     97                                                     }
     98                                                 }
     99                                             }
    100                                         }
    101                                     } catch (Throwable t) {
    102                                         IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + url + ", cause: " + t.getMessage(), t);
    103                                         exceptions.put(line, e);
    104                                     }
    105                                 }
    106                             } // end of while read lines
    107                         } finally {
    108                             reader.close();
    109                         }
    110                     } catch (Throwable t) {
    111                         logger.error("Exception when load extension class(interface: " +
    112                                 type + ", class file: " + url + ") in " + url, t);
    113                     }
    114                 } // end of while urls
    115             }
    116         } catch (Throwable t) {
    117             logger.error("Exception when load extension class(interface: " +
    118                     type + ", description file: " + fileName + ").", t);
    119         }
    120     }

    上述的方法分别从三个目录查找SPI文件并进行加载。在这里只有在META-INF/dubbo/internal/com.alibaba.dubbo.common.extension.ExtensionFactory中有值,内容如下:

    1 adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
    2 spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
    3 spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory

    其中AdaptiveExtensionFactory在类上具有@Adaptive注解,这个类会在后续去讲,这里先略过。

    执行过后,看一下:

    • cachedAdaptiveClass=class com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
    • extensionClasses=[{"spring","class com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory"}, {"spi", "class com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory"}],后续会这个集合存储在cachedClasses缓存中。

    上边一直在讲解getAdaptiveExtensionClass().newInstance()这句代码中的getAdaptiveExtensionClass(),此方法返回一个com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory类,之后来看一下其newInstance()代码,调用这个方法,默认会执行AdaptiveExtensionFactory的无参构造器。这里给出AdaptiveExtensionFactory的完整代码:

     1 package com.alibaba.dubbo.common.extension.factory;
     2 
     3 import com.alibaba.dubbo.common.extension.Adaptive;
     4 import com.alibaba.dubbo.common.extension.ExtensionFactory;
     5 import com.alibaba.dubbo.common.extension.ExtensionLoader;
     6 
     7 import java.util.ArrayList;
     8 import java.util.Collections;
     9 import java.util.List;
    10 
    11 /**
    12  * AdaptiveExtensionFactory
    13  */
    14 @Adaptive
    15 public class AdaptiveExtensionFactory implements ExtensionFactory {
    16     private final List<ExtensionFactory> factories;
    17 
    18     /**
    19      * 遍历cachedClasses中缓存的extensionClasses的key,之后根据key来实例化对应的实现类,最后放置到EXTENSION_INSTANCES缓存中
    20      */
    21     public AdaptiveExtensionFactory() {
    22         ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
    23         List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
    24         for (String name : loader.getSupportedExtensions()) {
    25             list.add(loader.getExtension(name));
    26         }
    27         factories = Collections.unmodifiableList(list);
    28     }
    29 
    30     public <T> T getExtension(Class<T> type, String name) {
    31         for (ExtensionFactory factory : factories) {
    32             T extension = factory.getExtension(type, name);
    33             if (extension != null) {
    34                 return extension;
    35             }
    36         }
    37         return null;
    38     }
    39 }

    从上可以看出,这个装饰类只是实例化好了各个ExtensionFactory(这里是SpiExtensionFactory和SpringExtensionFactory),后续通过工厂获取实现类实例都是由具体工厂来完成。

    来看一下实例化代码的地方,即loader.getExtension(name):

     1     /**
     2      * 从cachedInstances缓存中获取name对应的实例,如果没有,通过createExtension(name)创建,之后放入缓存
     3      * getExtension(String name)
     4      * --createExtension(String name)
     5      * ----injectExtension(T instance)
     6      */
     7     public T getExtension(String name) {
     8         if (name == null || name.length() == 0)
     9             throw new IllegalArgumentException("Extension name == null");
    10         if ("true".equals(name)) {
    11             return getDefaultExtension();
    12         }
    13         Holder<Object> holder = cachedInstances.get(name);
    14         if (holder == null) {
    15             cachedInstances.putIfAbsent(name, new Holder<Object>());
    16             holder = cachedInstances.get(name);
    17         }
    18         Object instance = holder.get();
    19         if (instance == null) {
    20             synchronized (holder) {
    21                 instance = holder.get();
    22                 if (instance == null) {
    23                     instance = createExtension(name);
    24                     holder.set(instance);
    25                 }
    26             }
    27         }
    28         return (T) instance;
    29     }

    来看一下创建createExtension(name):

     1     private T createExtension(String name) {
     2         /** 从cachedClasses缓存中获取所有的实现类map,之后通过name获取到对应的实现类的Class对象 */
     3         Class<?> clazz = getExtensionClasses().get(name);
     4         if (clazz == null) {
     5             throw findException(name);
     6         }
     7         try {
     8             /** 从EXTENSION_INSTANCES缓存中获取对应的实现类的Class对象,如果没有,直接创建,之后放入缓存 */
     9             T instance = (T) EXTENSION_INSTANCES.get(clazz);
    10             if (instance == null) {
    11                 EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
    12                 instance = (T) EXTENSION_INSTANCES.get(clazz);
    13             }
    14             injectExtension(instance);//ioc
    15             Set<Class<?>> wrapperClasses = cachedWrapperClasses;
    16             if (wrapperClasses != null && wrapperClasses.size() > 0) {
    17                 for (Class<?> wrapperClass : wrapperClasses) {
    18                     instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
    19                 }
    20             }
    21             return instance;
    22         } catch (Throwable t) {
    23             throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
    24                     type + ")  could not be instantiated: " + t.getMessage(), t);
    25         }
    26     }

    这里,就体现出来了dubbo-SPI比JDK-SPI的好处:dubbo-SPI不需要遍历所有的实现类来获取想要的实现类,可以直接通过name来获取。

    injectExtension(instance)和wrapper包装功能后续再说。

    到此为止,ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);这行代码的整个源码就讲述完成了。最后来看一下整个代码的执行结果。

    类变量

    • ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS
      • "interface com.alibaba.dubbo.rpc.Protocol" -> "com.alibaba.dubbo.common.extension.ExtensionLoader[com.alibaba.dubbo.rpc.Protocol]"
      • "interface com.alibaba.dubbo.common.extension.ExtensionFactory" -> "com.alibaba.dubbo.common.extension.ExtensionLoader[com.alibaba.dubbo.common.extension.ExtensionFactory]"
    • ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES
      • "class com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory" -> SpringExtensionFactory实例
      • "class com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory" -> SpiExtensionFactory实例

    ExtensionLoader<Protocol> loader的实例变量

    • Class<?> type = interface com.alibaba.dubbo.rpc.Protocol
    • ExtensionFactory objectFactory = AdaptiveExtensionFactory(适配类)
      • factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]

    总结:

    第一点:ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(Class<T> type)最终得到的实例变量是:

    • Class<?> type = interface T
    • ExtensionFactory objectFactory = AdaptiveExtensionFactory(适配类)
      • factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]

    第二点:ExtensionLoader<T>.getAdaptiveExtension()的调用层级

    1 ExtensionLoader<T>.getAdaptiveExtension()
    2 --createAdaptiveExtension()
    3 ----injectExtension(getAdaptiveExtensionClass())
    4 ------getAdaptiveExtensionClass()
    5 --------getExtensionClasses()//从spi文件中查找实现类上具有@Adaptive注解的类
    6 ----------loadExtensionClasses()
    7 ------------loadFile(Map<String, Class<?>> extensionClasses, String dir)
    8 --------createAdaptiveExtensionClass()//如果从spi文件中没有找到实现类上具有@Adaptive注解的类,则动态创建类

    最终返回的是创建好的Adaptive类,例如AdaptiveExtensionFactory实例。

    第三点:ExtensionLoader<T>.getExtension()的调用层级

    1 ExtensionLoader<T>.getExtension()
    2 --createExtension(String name)
    3 ----getExtensionClasses().get(name)//获取扩展类
    4 ----injectExtension(instance);//ioc
    5 ----wrapper包装;//aop

    最终返回的是创建好的具体实现类,例如SpringExtensionFactory实例。 

    至此,dubbo-spi源码解析完成!!!

  • 相关阅读:
    第二次,营造完整的人生(上)
    御风者(二)——狼王
    我的个人博客
    FTP 协议解析
    关于 Wireshark3 中 GeoIP 的问题
    CentOS8 NextCloud 私有云存储搭建
    Windows10 临时将线程绑定至指定CPU的方法
    CentOS8 yum/dnf 配置国内源(临时)
    Cknife流量分析
    samba + OPENldap 搭建文件共享服务器
  • 原文地址:https://www.cnblogs.com/java-zhao/p/7617285.html
Copyright © 2011-2022 走看看