• 第一章 dubbo源码解析目录


    重要的网址:

    第一个dubbo项目

    首先从https://github.com/alibaba/dubbo下载dubbo源码到本地,我们的第一个dubbo项目就是dubbo源码中的dubbo-demo子模块。

    代码结构如下:

    其中:

    • dubbo-demo-api是提供服务接口的模块
      • 在生产中,该模块会单独打成jar包,分别被provider和consumer依赖,provider实现该接口,consumer通过该接口引用provider实现的服务
    • dubbo-demo-provider是服务提供者
    • dubbo-demo-consumer是服务消费者

    一 dubbo-demo-api

    1 package com.alibaba.dubbo.demo;
    2 
    3 public interface DemoService {
    4     String sayHello(String name);
    5 }

    只提供了一个接口。

    二 dubbo-demo-provider

    1 配置文件

    src/main/resources/META-INF/spring/dubbo-demo-provider.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3        xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
     4        xmlns="http://www.springframework.org/schema/beans"
     5        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     6        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
     7 
     8     <!-- 提供方应用信息,用于计算依赖关系 -->
     9     <dubbo:application name="demo-provider"/>
    10 
    11     <!-- 使用zookeeper注册中心,并使用curator客户端 -->
    12     <dubbo:registry protocol="zookeeper" address="10.211.55.5:2181" client="curator"/>
    13 
    14     <!-- 使用dubbo协议在20880端口暴露服务 -->
    15     <dubbo:protocol name="dubbo" port="20880"/>
    16 
    17     <!-- 和本地bean一样实现服务 -->
    18     <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"/>
    19 
    20     <!-- 声明需要暴露的服务接口 -->
    21     <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService"/>
    22 </beans>

    配置项:

    • dubbo:application:指定应用名字,在生产中通常与artifactId相同
    • dubbo:registry:指定注册中心
      • protocol:使用的注册协议
      • address:注册中心地址
      • client:默认情况下,操作zookeeper的java客户端使用的是zkClient,这里使用curator
    • dubbo:protocol:指定服务暴露的协议和端口
    • dubbo:service:生命暴露的服务接口及其实现类

    2 provider提供服务接口实现

     1 package com.alibaba.dubbo.demo.provider;
     2 
     3 import com.alibaba.dubbo.demo.DemoService;
     4 import com.alibaba.dubbo.rpc.RpcContext;
     5 
     6 import java.text.SimpleDateFormat;
     7 import java.util.Date;
     8 
     9 public class DemoServiceImpl implements DemoService {
    10     public String sayHello(String name) {
    11         System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
    12         return "Hello " + name + ", response form provider: " + RpcContext.getContext().getLocalAddress();
    13     }
    14 }

    3 provider启动类

     1 package com.alibaba.dubbo.demo.provider;
     2 
     3 import org.springframework.context.support.ClassPathXmlApplicationContext;
     4 
     5 public class Provider {
     6     public static void main(String[] args) throws Exception {
     7         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"});
     8         context.start();
     9 
    10         System.in.read(); // 按任意键退出
    11     }
    12 }

    三 dubbo-demo-consumer

    1 配置文件

    src/main/resources/META-INF/spring/dubbo-demo-consumer.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3        xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
     4        xmlns="http://www.springframework.org/schema/beans"
     5        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     6        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
     7 
     8     <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
     9     <dubbo:application name="demo-consumer"/>
    10 
    11     <!-- 使用zookeeper注册中心,并使用curator客户端 -->
    12     <dubbo:registry protocol="zookeeper" address="10.211.55.5:2181" client="curator"/>
    13 
    14     <!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
    15     <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService"/>
    16 </beans>

    配置项:

    • dubbo:reference:指定引用的服务
      • check:检查注册中心是否有可用的 provider

    2 consumer启动类

     1 package com.alibaba.dubbo.demo.consumer;
     2 
     3 import com.alibaba.dubbo.demo.DemoService;
     4 import org.springframework.context.support.ClassPathXmlApplicationContext;
     5 
     6 public class Consumer {
     7     public static void main(String[] args) {
     8         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"});
     9         context.start();
    10 
    11         DemoService demoService = (DemoService) context.getBean("demoService"); // 获取远程服务代理
    12         String hello = demoService.sayHello("world"); // 执行远程方法
    13 
    14         System.out.println(hello); // 显示调用结果
    15     }
    16 }

     启动服务并且调用远程服务。

    四 启动服务

    1 启动provider

    启动成功后,会发现在zookeeper上创建了节点:

    /dubbo

    --/com.alibaba.dubbo.demo.DemoService

    ----/providers

    ------/dubbo://10.10.10.10:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=1393&side=provider&timestamp=1506831679007

    注意:

    • 所有dubbo相关的都会注册在“/dubbo”根节点下
    • 与当前暴露的接口服务相关的,都注册在“/dubbo/接口”下

    2 启动consumer

    启动成功后,会发现在zookeeper上创建了节点:

    /dubbo

    --/com.alibaba.dubbo.demo.DemoService

    ----/consumers

    ------/consumer://10.10.10.10/com.alibaba.dubbo.demo.DemoService?application=demo-consumer&category=consumers&check=false&dubbo=2.0.0&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=1434&side=consumer&timestamp=1506832498078

    之后,看到provider和consumer双方的互动输出,则表示rpc成功!

    第一个dubbo项目就结束了,dubbo-demo项目也可以查看http://dubbo.io/的例子。

    2.1 jdk-spi的实现原理

    dubbo-spi是在jdk-spi的基础上进行重写优化,下面看一下jdk-spi。

    一、作用

    • 为接口自动寻找实现类。

    二、实现方式

    • 标准制定者制定接口
    • 不同厂商编写针对于该接口的实现类,并在jar的“classpath:META-INF/services/全接口名称”文件中指定相应的实现类全类名
    • 开发者直接引入相应的jar,就可以实现为接口自动寻找实现类的功能

    三、使用方法

    注意:示例以Log体系为例,但是实际中的Log体系并不是这样来实现的。

    1、pom.xml

    1 <?xml version="1.0" encoding="UTF-8"?>
    2 <project xmlns="http://maven.apache.org/POM/4.0.0"
    3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5     <modelVersion>4.0.0</modelVersion>
    6     <groupId>com.hulk</groupId>
    7     <artifactId>java-spi</artifactId>
    8     <version>1.0-SNAPSHOT</version>
    9 </project>

    2、标准接口:com.hulk.javaspi.Log

    1 package com.hulk.javaspi;
    2 
    3 public interface Log {
    4     void execute();
    5 }

    3、具体实现1:com.hulk.javaspi.Log4j

    1 package com.hulk.javaspi;
    2 
    3 public class Log4j implements Log {
    4     @Override
    5     public void execute() {
    6         System.out.println("log4j ...");
    7     }
    8 }

    4、具体实现2:com.hulk.javaspi.Logback

    1 package com.hulk.javaspi;
    2 
    3 public class Logback implements Log {
    4     @Override
    5     public void execute() {
    6         System.out.println("logback ...");
    7     }
    8 }

    5、指定使用的实现文件:META-INF/services/com.hulk.javaspi.Log

    1 com.hulk.javaspi.Logback

    注意

    • 这里指定了实现类Logback,那么加载的时候就会自动为Log接口指定实现类为Logback。
    • 这里也可以指定两个实现类,那么在实际中使用哪一个实现类,就需要使用额外的手段来控制。
      1 com.hulk.javaspi.Logback
      2 com.hulk.javaspi.Log4j

    6、加载实现主类:com.hulk.javaspi.Main

     1 package com.hulk.javaspi;
     2 
     3 import java.util.Iterator;
     4 import java.util.ServiceLoader;
     5 
     6 public class Main {
     7     public static void main(String[] args) {
     8         ServiceLoader<Log> serviceLoader = ServiceLoader.load(Log.class);
     9         Iterator<Log> iterator = serviceLoader.iterator();
    10         while (iterator.hasNext()) {
    11             Log log = iterator.next();
    12             log.execute();
    13         }
    14     }
    15 }

    注意:

    • ServiceLoader不是实例化以后,就去读取配置文件中的具体实现,并进行实例化。而是等到使用迭代器去遍历的时候,才会加载对应的配置文件去解析,调用hasNext方法的时候会去加载配置文件进行解析,调用next方法的时候进行实例化并缓存 - 具体见“源码分析”

    现在来解析Main的源码。

    四、源码解析

    1、获取ServiceLoader

    1 ServiceLoader<Log> serviceLoader = ServiceLoader.load(Log.class);

    源码:

    首先来看一下ServiceLoader的6个属性

    1      private static final String PREFIX = "META-INF/services/";//定义实现类的接口文件所在的目录
    2      private final Class<S> service;//接口
    3      private final ClassLoader loader;//定位、加载、实例化实现类
    4      private final AccessControlContext acc;//权限控制上下文
    5      private LinkedHashMap<String,S> providers = new LinkedHashMap<>();//以初始化的顺序缓存<接口全名称, 实现类实例>
    6      private LazyIterator lookupIterator;//真正进行迭代的迭代器

    其中LazyIterator是ServiceLoader的一个内部类,在迭代部分会说。

     1     public static <S> ServiceLoader<S> load(Class<S> service) {
     2         ClassLoader cl = Thread.currentThread().getContextClassLoader();
     3         return ServiceLoader.load(service, cl);
     4     }
     5 
     6     public static <S> ServiceLoader<S> load(Class<S> service,
     7                                             ClassLoader loader) {
     8         return new ServiceLoader<>(service, loader);
     9     }
    10 
    11     private ServiceLoader(Class<S> svc, ClassLoader cl) {
    12         service = Objects.requireNonNull(svc, "Service interface cannot be null");
    13         loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
    14         acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
    15         reload();
    16     }
    17 
    18     public void reload() {
    19         providers.clear();//清空缓存
    20         lookupIterator = new LazyIterator(service, loader);
    21     }

    这样一个ServiceLoader实例就创建成功了。在创建的过程中,我们看到还实例化了一个LazyIterator,该类下边会说。

    2、获取迭代器并迭代

    1          Iterator<Log> iterator = serviceLoader.iterator();
    2          while (iterator.hasNext()) {
    3              Log log = iterator.next();
    4              log.execute();
    5          }

    外层迭代器:

     1     public Iterator<S> iterator() {
     2         return new Iterator<S>() {
     3 
     4             Iterator<Map.Entry<String,S>> knownProviders
     5                 = providers.entrySet().iterator();
     6 
     7             public boolean hasNext() {
     8                 if (knownProviders.hasNext())
     9                     return true;
    10                 return lookupIterator.hasNext();
    11             }
    12 
    13             public S next() {
    14                 if (knownProviders.hasNext())
    15                     return knownProviders.next().getValue();
    16                 return lookupIterator.next();
    17             }
    18 
    19             public void remove() {
    20                 throw new UnsupportedOperationException();
    21             }
    22 
    23         };
    24     }

     从查找过程hasNext()和迭代过程next()来看。

    • hasNext():先从provider(缓存)中查找,如果有,直接返回true;如果没有,通过LazyIterator来进行查找。
    • next():先从provider(缓存)中直接获取,如果有,直接返回实现类对象实例;如果没有,通过LazyIterator来进行获取。

    下面来看一下,LazyIterator这个类。首先看一下他的属性:

    1         Class<S> service;//接口
    2         ClassLoader loader;//类加载器
    3         Enumeration<URL> configs = null;//存放配置文件
    4         Iterator<String> pending = null;//存放配置文件中的内容,并存储为ArrayList,即存储多个实现类名称
    5         String nextName = null;//当前处理的实现类名称

    其中,service和loader在上述实例化ServiceLoader的时候就已经实例化好了。

    下面看一下hasNext():

     1         public boolean hasNext() {
     2             if (acc == null) {
     3                 return hasNextService();
     4             } else {
     5                 PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
     6                     public Boolean run() { return hasNextService(); }
     7                 };
     8                 return AccessController.doPrivileged(action, acc);
     9             }
    10         }
    11 
    12         private boolean hasNextService() {
    13             if (nextName != null) {
    14                 return true;
    15             }
    16             if (configs == null) {
    17                 try {
    18                     String fullName = PREFIX + service.getName();
    19                     if (loader == null)
    20                         configs = ClassLoader.getSystemResources(fullName);
    21                     else
    22                         configs = loader.getResources(fullName);
    23                 } catch (IOException x) {
    24                     fail(service, "Error locating configuration files", x);
    25                 }
    26             }
    27             while ((pending == null) || !pending.hasNext()) {
    28                 if (!configs.hasMoreElements()) {
    29                     return false;
    30                 }
    31                 pending = parse(service, configs.nextElement());
    32             }
    33             nextName = pending.next();
    34             return true;
    35         }

    hasNextService()中,核心实现如下:

    • 首先使用loader加载配置文件,此时找到了META-INF/services/com.hulk.javaspi.Log文件;
    • 然后解析这个配置文件,并将各个实现类名称存储在pending的ArrayList中; -->  此时[ com.hulk.javaspi.Logback ]
    • 最后指定nextName; --> 此时nextName=com.hulk.javaspi.Logback

     下面看一下next():

     1         public S next() {
     2             if (acc == null) {
     3                 return nextService();
     4             } else {
     5                 PrivilegedAction<S> action = new PrivilegedAction<S>() {
     6                     public S run() { return nextService(); }
     7                 };
     8                 return AccessController.doPrivileged(action, acc);
     9             }
    10         }
    11 
    12         private S nextService() {
    13             if (!hasNextService())
    14                 throw new NoSuchElementException();
    15             String cn = nextName;
    16             nextName = null;
    17             Class<?> c = null;
    18             try {
    19                 c = Class.forName(cn, false, loader);
    20             } catch (ClassNotFoundException x) {
    21                 fail(service,
    22                      "Provider " + cn + " not found");
    23             }
    24             if (!service.isAssignableFrom(c)) {
    25                 fail(service,
    26                      "Provider " + cn  + " not a subtype");
    27             }
    28             try {
    29                 S p = service.cast(c.newInstance());
    30                 providers.put(cn, p);
    31                 return p;
    32             } catch (Throwable x) {
    33                 fail(service,
    34                      "Provider " + cn + " could not be instantiated",
    35                      x);
    36             }
    37             throw new Error();          // This cannot happen
    38         }

    nextService()中,核心实现如下:

    • 首先加载nextName代表的类Class,这里为com.hulk.javaspi.Logback;
    • 之后创建该类的实例,并转型为所需的接口类型
    • 最后存储在provider中,供后续查找,最后返回转型后的实现类实例。

    再next()之后,拿到实现类实例后,就可以执行其具体的方法了。

    五、缺点

    • 查找一个具体的实现需要遍历查找,耗时;-->此时就体现出Collection相较于Map差的地方,map可以直接根据key来获取具体的实现 (dubbo-spi实现了根据key获取具体实现的方式)

    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内核之ioc源码解析

    dubbo的IOC具体实现在:T injectExtension(T instance)方法中。该方法只在三个地方被使用:

    1 createAdaptiveExtension()
    2 --injectExtension((T) getAdaptiveExtensionClass().newInstance()) //为创建好的AdaptiveExtensionClass实例进行属性注入
    3 
    4 createExtension(String name)
    5 --injectExtension(instance) //为创建好的Extension实例进行属性注入
    6 --injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)) //为创建好的wrapperClass实例进行属性注入

    来看一下源码:

     1     /**
     2      * dubbo-IOC的核心
     3      */
     4     private T injectExtension(T instance) {
     5         try {
     6             if (objectFactory != null) {
     7                 for (Method method : instance.getClass().getMethods()) {
     8                     if (method.getName().startsWith("set") && method.getParameterTypes().length == 1
     9                         && Modifier.isPublic(method.getModifiers())) {//一个参数的public的setXXX(T param)方法.例如,setName(String name)
    10                         Class<?> pt = method.getParameterTypes()[0];//参数param的类型T,eg.String
    11                         try {
    12                             String property = method.getName().length() > 3
    13                                 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";//获取属性名XXX, eg.name
    14                             Object object = objectFactory.getExtension(pt, property);//实例化参数
    15                             if (object != null) {
    16                                 //执行instance.method(object)方法,这里就是执行instance的setter方法,进行setter注入
    17                                 method.invoke(instance, object);
    18                             }
    19                         } catch (Exception e) {
    20                             logger.error("fail to inject via method " + method.getName() + " of interface "
    21                                          + type.getName() + ": " + e.getMessage(),
    22                                 e);
    23                         }
    24                     }
    25                 }
    26             }
    27         } catch (Exception e) {
    28             logger.error(e.getMessage(), e);
    29         }
    30         return instance;
    31     }

    整个方法的作用就是通过instance对象实例的setter方法为instance的属性赋值,完成setter注入,即IOC的最经典的注入方式。

    详细步骤:

    • 获取instance的setter方法,通过setter方法获取属性名称property和属性类型pt(即paramType的简写)
    • 使用objectFactory创建一个property名称(类型为pt)的对象实例
    • 执行instance的setter方法,注入property实例

    其中,比较重要的就是:Object object = objectFactory.getExtension(pt, property);这个方法。其中的objectFactory=AdaptiveExtensionFactory实例,其属性factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]。

    看一下源码:

     1     private final List<ExtensionFactory> factories;
     2 
     3     public <T> T getExtension(Class<T> type, String name) {
     4         /**
     5          * 先调用SpiExtensionFactory来实例化;
     6          * 如果不行,再使用SpringExtensionFactory来实例化
     7          */
     8         for (ExtensionFactory factory : factories) {
     9             T extension = factory.getExtension(type, name);
    10             if (extension != null) {
    11                 return extension;
    12             }
    13         }
    14         return null;
    15     }

    看一下SpiExtensionFactory的源码:

     1 public class SpiExtensionFactory implements ExtensionFactory {
     2     public <T> T getExtension(Class<T> type, String name) {
     3         if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {//type是接口且必须具有@SPI注解
     4             ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
     5             if (loader.getSupportedExtensions().size() > 0) {//获取type的所有ExtensionClasses实现的key
     6                 return loader.getAdaptiveExtension();//获取type的装饰类,如果有@Adaptive注解的类,则返回该类的实例,否则返回一个动态代理类的实例(例如Protocol$Adpative的实例)
     7             }
     8         }
     9         return null;
    10     }
    11 }

    从这里我们可以看出dubbo-SPI的另外一个好处:可以为SPI实现类注入SPI的装饰类或动态代理类。

    看一下SpringExtensionFactory的源码:

     1 public class SpringExtensionFactory implements ExtensionFactory {
     2     private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
     3     
     4     public static void addApplicationContext(ApplicationContext context) {
     5         contexts.add(context);
     6     }
     7 
     8     public static void removeApplicationContext(ApplicationContext context) {
     9         contexts.remove(context);
    10     }
    11 
    12     @SuppressWarnings("unchecked")
    13     public <T> T getExtension(Class<T> type, String name) {
    14         for (ApplicationContext context : contexts) {
    15             if (context.containsBean(name)) {//该context是否包含name的bean
    16                 Object bean = context.getBean(name);//获取name的bean,如果是懒加载或多例的bean,此时会实例化name的bean
    17                 if (type.isInstance(bean)) {//如果obj的类型是type或其子类,与instanceof相同
    18                     return (T) bean;
    19                 }
    20             }
    21         }
    22         return null;
    23     }
    24 }

    至此,IOC就干完了。但是有一个遗留问题,ApplicationContext是什么时候加入到contexts中呢?当讲解ServiceBean的时候来说。

    第四章 dubbo内核之aop源码解析

    1         ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);
    2         final Protocol dubboProtocol = loader.getExtension("dubbo");
    3         final Protocol adaptiveExtension = loader.getAdaptiveExtension();

    第一行代码在2.2 dubbo-spi源码解析中讲过,本节来看第二行代码。

    一、获取一个ExtensionLoader

    第一行代码后获得的loader:

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

    二、getExtension("dubbo")

    调用层级:

    1 ExtensionLoader<T>.getExtension()
    2 --createExtension(String name)
    3 ----getExtensionClasses().get(name)//获取扩展类
    4 ------loadExtensionClasses()
    5 --------loadFile(Map<String, Class<?>> extensionClasses, String dir)
    6 ----injectExtension(instance);//ioc
    7 ----wrapper包装;//aop

    createExtension(String 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);
    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: " + type
    24                                             + ")  could not be instantiated: " + t.getMessage(),
    25                 t);
    26         }
    27     }

    这里,先给出META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol内容:

     1 registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
     2 dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
     3 filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
     4 listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
     5 mock=com.alibaba.dubbo.rpc.support.MockProtocol
     6 injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
     7 rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
     8 hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
     9 com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
    10 com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
    11 thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
    12 memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
    13 redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol

    com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper和com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper,这两个类不含有@Adaptive注解且具有含有Protocol的单参构造器,符合这样条件的会被列入AOP增强类。放置在loader的私有属性cachedWrapperClasses中。

    此时的loader:

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

    再来看createExtension(String name)中的红色部分,就是今天的重点AOP。如上所讲,我在cachedWrapperClasses中缓存了两个AOP增强类:class ProtocolListenerWrapper和class ProtocolFilterWrapper。

    首先是获取ProtocolListenerWrapper的单参构造器,然后创建ProtocolListenerWrapper实例,最后完成对ProtocolListenerWrapper实例进行属性注入,注意此时的instance=ProtocolListenerWrapper实例,而不再是之前的DubboProtocol实例了。之后使用ProtocolFilterWrapper以同样的方式进行包装,只是此时ProtocolFilterWrapper包装的是ProtocolListenerWrapper实例,也就是类似于这样的关系:

    1 instance = ProtocolFilterWrapper实例 {
    2       protocol = ProtocolListenerWrapper实例 {
    3           protocol = DubboProtocol实例
    4       }  
    5 }    

    来看一下ProtocolListenerWrapper源码:

     1 package com.alibaba.dubbo.rpc.protocol;
     2 
     3 import com.alibaba.dubbo.common.Constants;
     4 import com.alibaba.dubbo.common.URL;
     5 import com.alibaba.dubbo.common.extension.ExtensionLoader;
     6 import com.alibaba.dubbo.rpc.Exporter;
     7 import com.alibaba.dubbo.rpc.ExporterListener;
     8 import com.alibaba.dubbo.rpc.Invoker;
     9 import com.alibaba.dubbo.rpc.InvokerListener;
    10 import com.alibaba.dubbo.rpc.Protocol;
    11 import com.alibaba.dubbo.rpc.RpcException;
    12 import com.alibaba.dubbo.rpc.listener.ListenerExporterWrapper;
    13 import com.alibaba.dubbo.rpc.listener.ListenerInvokerWrapper;
    14 
    15 import java.util.Collections;
    16 
    17 public class ProtocolListenerWrapper implements Protocol {
    18     private final Protocol protocol;
    19 
    20     public ProtocolListenerWrapper(Protocol protocol) {
    21         if (protocol == null) {
    22             throw new IllegalArgumentException("protocol == null");
    23         }
    24         this.protocol = protocol;
    25     }
    26 
    27     public int getDefaultPort() {
    28         return protocol.getDefaultPort();
    29     }
    30 
    31     public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    32         if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
    33             return protocol.export(invoker);
    34         }
    35         return new ListenerExporterWrapper<T>(protocol.export(invoker),
    36                 Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
    37                         .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
    38     }
    39 
    40     public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    41         if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
    42             return protocol.refer(type, url);
    43         }
    44         return new ListenerInvokerWrapper<T>(protocol.refer(type, url),
    45                 Collections.unmodifiableList(
    46                         ExtensionLoader.getExtensionLoader(InvokerListener.class)
    47                                 .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY)));
    48     }
    49 
    50     public void destroy() {
    51         protocol.destroy();
    52     }
    53 }

    这里的方法不做讲解,等到了服务提供者暴露服务和服务消费者引用服务的时候再做讲解。

    ProtocolFilterWrapper源码如下:

     1 package com.alibaba.dubbo.rpc.protocol;
     2 
     3 import com.alibaba.dubbo.common.Constants;
     4 import com.alibaba.dubbo.common.URL;
     5 import com.alibaba.dubbo.common.extension.ExtensionLoader;
     6 import com.alibaba.dubbo.rpc.Exporter;
     7 import com.alibaba.dubbo.rpc.Filter;
     8 import com.alibaba.dubbo.rpc.Invocation;
     9 import com.alibaba.dubbo.rpc.Invoker;
    10 import com.alibaba.dubbo.rpc.Protocol;
    11 import com.alibaba.dubbo.rpc.Result;
    12 import com.alibaba.dubbo.rpc.RpcException;
    13 
    14 import java.util.List;
    15 
    16 public class ProtocolFilterWrapper implements Protocol {
    17     private final Protocol protocol;
    18 
    19     public ProtocolFilterWrapper(Protocol protocol) {
    20         if (protocol == null) {
    21             throw new IllegalArgumentException("protocol == null");
    22         }
    23         this.protocol = protocol;
    24     }
    25 
    26     private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    27         Invoker<T> last = invoker;
    28         List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
    29         if (filters.size() > 0) {
    30             for (int i = filters.size() - 1; i >= 0; i--) {
    31                 final Filter filter = filters.get(i);
    32                 final Invoker<T> next = last;
    33                 last = new Invoker<T>() {
    34 
    35                     public Class<T> getInterface() {
    36                         return invoker.getInterface();
    37                     }
    38 
    39                     public URL getUrl() {
    40                         return invoker.getUrl();
    41                     }
    42 
    43                     public boolean isAvailable() {
    44                         return invoker.isAvailable();
    45                     }
    46 
    47                     public Result invoke(Invocation invocation) throws RpcException {
    48                         return filter.invoke(next, invocation);
    49                     }
    50 
    51                     public void destroy() {
    52                         invoker.destroy();
    53                     }
    54 
    55                     @Override
    56                     public String toString() {
    57                         return invoker.toString();
    58                     }
    59                 };
    60             }
    61         }
    62         return last;
    63     }
    64 
    65     public int getDefaultPort() {
    66         return protocol.getDefaultPort();
    67     }
    68 
    69     public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    70         if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
    71             return protocol.export(invoker);
    72         }
    73         return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
    74     }
    75 
    76     public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    77         if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
    78             return protocol.refer(type, url);
    79         }
    80         return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
    81     }
    82 
    83     public void destroy() {
    84         protocol.destroy();
    85     }
    86 }

    这里的方法不做讲解,等到了服务提供者暴露服务和服务消费者引用服务的时候再做讲解。

    最后返回的instance是ProtocolFilterWrapper对象,也就是说final Protocol dubboProtocol = loader.getExtension("dubbo");这句代码最后的dubboProtocol是ProtocolFilterWrapper实例。

    至此,aop结束。 

    5.1 javassist基本使用

    假设要使用javassist创建一个类:

     1 package com.alibaba.dubbo.demo.test;
     2 
     3 public class Emp {
     4     //属性
     5     private int    account;
     6     private String name;
     7 
     8     //构造方法
     9     public Emp() {
    10         this.account = 1;
    11         this.name = "xiaona";
    12     }
    13 
    14     //getter
    15     public int getAccount() {
    16         return account;
    17     }
    18 
    19     //setter
    20     public void setAccount(int account) {
    21         this.account = account;
    22     }
    23 
    24     public String getName() {
    25         return name;
    26     }
    27 
    28     public void setName(String name) {
    29         this.name = name;
    30     }
    31 
    32     //普通方法
    33     public void commonMethod() {
    34         System.out.println("haha");
    35     }
    36 }

    该类包含属性/构造方法/getter/setter/普通方法。

    使用javassist来创建类:

     1 package com.alibaba.dubbo.demo.test;
     2 
     3 import javassist.ClassPool;
     4 import javassist.CtClass;
     5 import javassist.CtConstructor;
     6 import javassist.CtField;
     7 import javassist.CtMethod;
     8 import javassist.CtNewMethod;
     9 import javassist.Modifier;
    10 
    11 import java.io.File;
    12 import java.io.FileOutputStream;
    13 
    14 public class TestJavassitCompiler {
    15     public static void main(String[] args) throws Exception {
    16         ClassPool pool = ClassPool.getDefault();
    17         CtClass ctClass = pool.makeClass("com.alibaba.dubbo.demo.test.Emp");
    18         //添加属性:private String name
    19         CtField nameField = new CtField(pool.getCtClass("java.lang.String"), "name", ctClass);
    20         nameField.setModifiers(Modifier.PRIVATE);
    21         ctClass.addField(nameField);
    22         //添加属性:private int account
    23         CtField accountField = new CtField(pool.getCtClass("int"), "account", ctClass);
    24         accountField.setModifiers(Modifier.PRIVATE);
    25         ctClass.addField(accountField);
    26         //getter和setter
    27         ctClass.addMethod(CtNewMethod.getter("getName", nameField));
    28         ctClass.addMethod(CtNewMethod.setter("setName", nameField));
    29         ctClass.addMethod(CtNewMethod.getter("getAccount", accountField));
    30         ctClass.addMethod(CtNewMethod.setter("setAccount", accountField));
    31         //创建构造器
    32         CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, ctClass);
    33         String body = new StringBuilder("{\nthis.account = 1;\nthis.name = \"xiaona\";\n}").toString();
    34         ctConstructor.setBody(body);
    35         ctClass.addConstructor(ctConstructor);
    36         //普通方法
    37         CtMethod ctMethod = new CtMethod(CtClass.voidType, "commonMethod", new CtClass[] {}, ctClass);
    38         ctMethod.setModifiers(Modifier.PUBLIC);
    39         ctMethod.setBody(new StringBuilder("{\n System.out.println(\"haha\"); \n}").toString());
    40         ctClass.addMethod(ctMethod);
    41 
    42         Class<?> clazz = ctClass.toClass();
    43         Object obj = clazz.newInstance();
    44         obj.getClass().getMethod("commonMethod", new Class[] {}).invoke(obj, new Object[] {});//方法调用
    45 
    46         /**
    47          * 将字节码输出到文件中
    48          */
    49         byte[] codeByteArray = ctClass.toBytecode();
    50         FileOutputStream fos = new FileOutputStream(new File("/Users/jigangzhao/Desktop/Emp.class"));
    51         fos.write(codeByteArray);
    52         fos.close();
    53     }
    54 }

    之后可以使用javap命令来看一下/Users/jigangzhao/Desktop/Emp.class文件。

    关于javassit的API请查看:

    https://github.com/jboss-javassist/javassist/wiki/Tutorial-1

    5.2 dubbo-compiler源码解析

     
    1         ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class);
    2         final Protocol dubboProtocol = loader.getExtension("dubbo");
    3         final Protocol adaptiveExtension = loader.getAdaptiveExtension();

    2.2 dubbo-spi源码解析讲了第一句,在第四章 dubbo内核之aop源码解析讲了第二句,本章来讲最后一句。

    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注解的类,则动态创建类

    这里最后执行到了createAdaptiveExtensionClass()方法。

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

    一 构造代码串

    createAdaptiveExtensionClassCode()方法中会判断如果一个类中没有@Adaptive注解的方法,则直接抛出IllegalStateException异常;否则,会为有@Adaptive注解的方法构造代码,而没有@Adaptive注解的方法直接抛出UnsupportedOperationException异常。

    构造出的结果为:

     1 package com.alibaba.dubbo.rpc;
     2 
     3 import com.alibaba.dubbo.common.extension.ExtensionLoader;
     4 
     5 public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
     6     public void destroy() {
     7         throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
     8     }
     9     public int getDefaultPort() {
    10         throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    11     }
    12     public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
    13         if (arg1 == null)
    14             throw new IllegalArgumentException("url == null");
    15         com.alibaba.dubbo.common.URL url = arg1;
    16         String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
    17         if(extName == null)
    18             throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
    19         com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
    20         return extension.refer(arg0, arg1);
    21     }
    22     public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
    23         if (arg0 == null)
    24             throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
    25         if (arg0.getUrl() == null)
    26             throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
    27         com.alibaba.dubbo.common.URL url = arg0.getUrl();
    28         String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
    29         if(extName == null)
    30             throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
    31         com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
    32         return extension.export(arg0);
    33     }
    34 }

    说明:

    • 该生成类在dubbo2.5.3中export和refer方法声明处的异常抛出是错的(在dubbo2.5.4改正了);
    • 类名在dubbo2.5.4之前(包含2.5.4)也是错的Protocol$Adpative,dubbo2.5.5改正了。

    二 获取Compiler装饰类

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

    先看一下com.alibaba.dubbo.common.compiler.Compiler接口:

    1 @SPI("javassist")
    2 public interface Compiler {
    3     Class<?> compile(String code, ClassLoader classLoader);
    4 }

    @SPI的默认值为javassist,根据上一节的经验,默认获取的Compiler接口的实现类将是META-INF/dubbo/internal/com.alibaba.dubbo.common.compiler.Compiler文件中的key为javassit的实现类。文件内容如下:

    1 adaptive=com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler
    2 jdk=com.alibaba.dubbo.common.compiler.support.JdkCompiler
    3 javassist=com.alibaba.dubbo.common.compiler.support.JavassistCompiler

    根据上一节对ExtensionFactory的getAdaptiveExtension()的讲解,我们最终获取到的Compiler的AdaptiveExtension将是com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler。

    来看源码,首先是获取ExtensionLoader<com.alibaba.dubbo.common.compiler.Compiler> loader,最终的loader包含如下属性:

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

    之后,是loader.getAdaptiveExtension()。

    在该方法中,首先会调用createAdaptiveExtension()创建实例,之后放入缓存,然后返回。

     1     private T createAdaptiveExtension() {
     2         try {
     3             return injectExtension((T) getAdaptiveExtensionClass().newInstance());
     4         } catch (Exception e) {
     5             throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(),
     6                 e);
     7         }
     8     }
     9 
    10     private Class<?> getAdaptiveExtensionClass() {
    11         /**
    12          * 获取ExtensionClasses和适配类
    13          * 其中适配类cachedAdaptiveClass如果不存在,则需要使用createAdaptiveExtensionClass()进行创建.
    14          */
    15         getExtensionClasses();
    16         if (cachedAdaptiveClass != null) {
    17             return cachedAdaptiveClass;
    18         }
    19         return cachedAdaptiveClass = createAdaptiveExtensionClass();
    20     }

    在createAdaptiveExtension()中首先会调用getAdaptiveExtensionClass()获取ExtensionClasses和修饰类,之后将修饰类返回。根据META-INF/dubbo/internal/com.alibaba.dubbo.common.compiler.Compiler文件的内容,最后返回

    • ExtensionClasses
      • "jdk" -> "class com.alibaba.dubbo.common.compiler.support.JdkCompiler"
      • "javassist" -> "class com.alibaba.dubbo.common.compiler.support.JavassistCompiler"
    • cachedAdaptiveClass=class com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler

    之后调用AdaptiveCompiler的无参构造器创建AdaptiveCompiler对象实例,然后执行injectExtension(T instance)(这里没起作用)为AdaptiveCompiler对象实例注入相应的属性(AdaptiveCompiler必须提供相应的setter方法),最后返回AdaptiveCompiler对象实例。

    三 编译代码并加载为Class<?>对象

    创建好AdaptiveCompiler对象实例之后,然后执行下面的方法。

    Class<?> compile(String code, ClassLoader classLoader)

    看一下AdaptiveCompiler全部源码:

     1 @Adaptive
     2 public class AdaptiveCompiler implements Compiler {
     3     private static volatile String DEFAULT_COMPILER;//默认的编译器的名字
     4 
     5     public static void setDefaultCompiler(String compiler) {
     6         DEFAULT_COMPILER = compiler;
     7     }
     8 
     9     /**
    10      * 典型的动态代理,在代理类中,存放着真实对象,使用真实对象执行相应的方法
    11      */
    12     public Class<?> compile(String code, ClassLoader classLoader) {
    13         Compiler compiler;
    14         ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
    15         String name = DEFAULT_COMPILER; // copy reference
    16         if (name != null && name.length() > 0) {
    17             compiler = loader.getExtension(name);//获取名字为name的实现类的实例,在获取的过程中会完成IOC和AOP
    18         } else {
    19             compiler = loader.getDefaultExtension();//获取默认的JavassitCompiler,调用getExtension(cachedDefaultName)
    20         }
    21         return compiler.compile(code, classLoader);//根据获取到的实现类compiler实例,来执行真正的动态生成类的代码
    22     }
    23 }

    这里执行的是compiler = loader.getDefaultExtension(),该方法不说了,就是调用了getExtension(cachedDefaultName)生成一个JavassistCompiler的实例。之后就是执行JavassistCompiler的compile(String code, ClassLoader classLoader)方法。

     1 package com.alibaba.dubbo.common.compiler.support;
     2 
     3 import com.alibaba.dubbo.common.compiler.Compiler;
     4 import com.alibaba.dubbo.common.utils.ClassHelper;
     5 
     6 import java.util.regex.Matcher;
     7 import java.util.regex.Pattern;
     8 
     9 /**
    10  * Abstract compiler. (SPI, Prototype, ThreadSafe)
    11  */
    12 public abstract class AbstractCompiler implements Compiler {
    13     private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\s+([$_a-zA-Z][$_a-zA-Z0-9\\.]*);");
    14     private static final Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s+");
    15 
    16     /**
    17      * 1 根据正则表达式从code中获取包名和类名,组成全类名
    18      * 2 根据全类名使用Class.forName创建Class<?>,如果该类在jvm中存在,则成功,否则抛出ClassNotFoundException,
    19      *   执行doCompile方法。
    20      */
    21     public Class<?> compile(String code, ClassLoader classLoader) {
    22         code = code.trim();
    23         Matcher matcher = PACKAGE_PATTERN.matcher(code);
    24         String pkg;
    25         if (matcher.find()) {
    26             pkg = matcher.group(1);
    27         } else {
    28             pkg = "";
    29         }
    30         matcher = CLASS_PATTERN.matcher(code);
    31         String cls;
    32         if (matcher.find()) {
    33             cls = matcher.group(1);
    34         } else {
    35             throw new IllegalArgumentException("No such class name in " + code);
    36         }
    37         String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls : cls;
    38         try {
    39             return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass()));
    40         } catch (ClassNotFoundException e) {
    41             if (!code.endsWith("}")) {
    42                 throw new IllegalStateException("The java code not endsWith \"}\", code: \n" + code + "\n");
    43             }
    44             try {
    45                 return doCompile(className, code);
    46             } catch (RuntimeException t) {
    47                 throw t;
    48             } catch (Throwable t) {
    49                 throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: \n" + code + "\n, stack: " + ClassUtils.toString(t));
    50             }
    51         }
    52     }
    53 
    54     protected abstract Class<?> doCompile(String name, String source) throws Throwable;
    55 }

    该方法会执行JavassistCompiler的Class<?> doCompile(String name, String source)方法了,在该方法中,使用正则表达式对传入的源码解析成属性方法等,并使用javassist的API创建Class<?>。

    最后,该final Protocol adaptiveExtension = loader.getAdaptiveExtension();代码返回的adaptiveExtension = Protocol$Adaptive实例。

    总结(再啰嗦一遍):

    • ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()最终返回的是:AdaptiveExtensionFactory实例,其属性factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]
    • 不管是获取哪一个SPI接口(除了ExtensionFactory.接口)的ExtensionLoader,最终一定会有一个objectFactory=上述的AdaptiveExtensionFactory实例
    • getAdaptiveExtension():作用就是获取一个装饰类或动态代理类的实例, 如果有@Adaptive注解的类,则直接返回该类的实例,否则返回一个动态代理类的实例(例如Protocol$Adaptive的实例),之后完成属性注入(dubbo-IOC),最后返回实例。
    • getExtension(String key):作用就是从extensionClasses(即指定SPI接口的没有@Adaptive的实现类)获取指定key的extensionClass,并且实例化,之后完成属性注入(dubbo-IOC),再之后完成dubbo-AOP,最后返回实例。
  • 相关阅读:
    java前三章总结
    Java入门第二章
    java编程入门小结
    Java入门第二章
    java预习易错点
    计算机基础
    切换卡
    ajax
    水印4
    shuiyin3
  • 原文地址:https://www.cnblogs.com/hanease/p/16295133.html
Copyright © 2020-2023  润新知