dubbo SPI 实现详解

我们知道 dubbo 的扩展性非常强,扩展点非常多,这些扩展都是靠 SPI 来加载的,但是dubbo并没有使用标准的SPI而是选择了自己实现,这又是为什么呢?

JDK SPI机制

jdk的SPI设计是为了可以面向接口编程,使第三方可以更好的对接口进行扩展实现,而使用方无需指定实现类,符合软件设计的可插拔原则,典型的使用场景如 jdbc,我们知道在使用数据库时我们只需要将对应数据库的驱动包引入即可,无需额外编码,用过 SLF4J 的同学肯定也知道项目中放一个实现了 SLF4J 的对应接口的实现就可以直接使用了,无需编码指定具体实现类,这就是 SPI 的功劳。但很多组件都没有基于原始的 SPI 做扩展而是选择在 SPI 的原理基础上自己实现,原因是 JDK 原生的 SPI 有一些局限性。

JDK的SPI实现有以下问题:

  1. 会默认实例化所有扩展,不能按需加载,如果扩展多而且大多数又用不到甚至某些还比较耗费资源或者加载比较慢就会白白浪费资源浪费时间
  2. 获取扩展时只能通过iterator的方式获取扩展,不能用key获取,查找时不太方便
  3. 扩展加载失败时提示信息不友好,甚至找不到是哪个扩展加载失败了

dubbo SPI机制

dubbo官网也写了其 SPI的实现机制,总结下可以得到如下信息:

  1. dubbo 的 SPI 是按需加载,不会初始化所有扩展类
  2. 每个扩展可以有一个名字,加载失败时可以根据名字找到具体的加载失败扩展名,获取扩展时也能根据名称获取,方便使用
  3. 增加了对扩展点 IoC 和 AOP 的支持,一个扩展实现可以通过setter注入到其他扩展实现,还有 Wrapper 实现会自动包装最终实现类,且会自动通过构造器注入实际实现类,ExtensionLoader 在加载扩展点时,如果加载到的扩展点有拷贝构造函数,则判定为扩展点 Wrapper 类。
  4. 动态扩展自适应、自动激活机制,即被注解 @Adaptive 的方法会根据注解中的key运行时适配其实现类,自动激活是指被 @Activate 标记的实现类支持自定义加载条件

dubbo 的许多模块都和 SPI 密切相关,理解 dubbo 的 SPI 实现机制对阅读 dubbo 源码会有很大助益;下面从一些核心注解和类逐一进行讲解。

注解 @SPI

这个注解用在接口类上,表示其是一个可扩展类,dubbo 的 SPI 实现会在获取扩展实现是检查接口类是否带有该注解,否则报错;该注解支持设定默认扩展名称,如 dubbo 的 Protocol 接口指定了 dubbo 为其默认实现类,那 dubbo 这个 key又是怎么来的呢,我们来看看 dubbo 扩展的配置格式,在 DubboProtocol 类的模块下 META-INF/dubbo/internal 目录中有一个 com.alibaba.dubbo.rpc.Protocol 文件,他是以扩展实现的接口名命名的 ,文件中的内容为 dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol,可以看到它是一个 key=value 的格式,dubbo 这个key即代表了value这个实现类。

注解 @Adaptive

该注解代表其是一个自适应接口或者类,该注解可以用在接口类或者方法上,表示方法或接口为自适应接口,用在接口类上表示该类的所有方法都为自适应方法,Adaptive 注解提供了一个可以运行时动态指定实现类的机制,以 Transporter 为例:

@SPI("netty") // 默认实现类为 netty
public interface Transporter {
    /**
     * 如果Adaptive注解中有参数则按照Adaptive的参数依次查找url,优先级为 Constants.SERVER_KEY、Constants.TRANSPORTER_KEY、netty
     * 体现在使用方式上就是
     * 生成的代码为 url.getParameter("server", url.getParameter("transporter", "netty")); 
     * 更详细的解释:1.查找 url中参数 server为key的value,如果有则以此为实现类,否则继续查找 transporter key的value,如果依然不存在则以 netty 为value的默认值,而默认值 netty 来自于 @SPI("netty") 注解
    */
    @Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})
    Server bind(URL url, ChannelHandler handler) throws RemotingException;

    @Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})
    Client connect(URL url, ChannelHandler handler) throws RemotingException;
}

该注解还可以用在具体的实现类上,如 AdaptiveExtensionFactory 表明该类是一个适配器实现类,当使用getAdaptiveExtension 方法时会优先返回该类而不再使用编译器动态生成适配器类XXX$Adpative

注解 @Activate

指定该扩展的使用条件,默认即所有情况下都加载,典型场景是 dubbo 的 Filter,其使用方式为 ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, "provider|consumer"),其返回的是一个 扩展类列表。

接口 ExtensionFactory

指定扩展获取的方式,值得一提的是 ExtensionFactory 本身也是带有 @SPI 注解的,也就是说他是依赖 dubbo 本身的 SPI 实现的。该接口一共有3个实现类:

  • SpiExtensionFactory 通过 dubbo SPI机制获取扩展
  • SpringExtensionFactory 通过 Spring IOC 获取扩展
  • AdaptiveExtensionFactory ExtensionFactory的适配器类,使用 ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()方法时返回该类

Wrapper 机制

ExtensionLoader 在加载扩展点时,如果加载到的扩展点的构造函数是以该扩展点的接口为入参的,则判定为扩展点 Wrapper 类。如 MockClusterWrapper 其构造器为

public class MockClusterWrapper implements Cluster {
    // 典型的 Wrapper 构造器
    public MockClusterWrapper(Cluster cluster) {
        this.cluster = cluster;
    }
}

Wrapper 类的用处是 SPI 在返回具体的扩展实现类时会用 Wrapper 类包装一下再返回,返回的实际上是一个 Wrapper 类的实例,同一个接口的 Wrapper 类可以有多个,会层层包装再返回,Wrapper 类的作用是将一些公共逻辑放到 Wrapper 类中进行复用,其实就是一个装饰器模式增强,dubbo 中大量使用装饰器模式进行编码,以此实现层次化设计,代码的复用性很高

自动注入

dubbo用自动注入的方式实现了扩展类之间相互依赖的问题,在创建扩展实现类实例后会对其setter方法进行扫描,如果方法参数类型是扩展类型就调用反射进行setter注入

注解 @DisableInject

该注解顾名思义是对一些不希望自动注入的属性进行标记,用在setter方法上

ExtensionLoader

dubbo 的 SPI 实现都在 ExtensionLoader 这个类中,代码足足有一千多行,下面我们从源码上来看看它是怎么实现的。

  • public static ExtensionLoader getExtensionLoader(Class type)

    /**
     * 获取一个接口的 ExtensionLoader 实例,每个扩展类都会创建一个ExtensionLoader实例
     * 要获取一个扩展接口的相关信息都需要先获取  ExtensionLoader
    */
    public static  ExtensionLoader getExtensionLoader(Class type) {
      // 判空
      if (type == null)
          throw new IllegalArgumentException("Extension type == null");
      //必须是接口类
      if (!type.isInterface()) {
          throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
      }
      //必须被 @SPI 注解
      if (!withExtensionAnnotation(type)) {
          throw new IllegalArgumentException("Extension type(" + type +
                  ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
      }
      // 先查缓存
      ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
      // 缓存不存在则创建
      if (loader == null) {
          EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
          loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
      }
      return loader;
    }
  • public T getExtension(String name)

    /**
     * 根据扩展名获取扩展实现类实例
     */
     public T getExtension(String name) {
      if (name == null || name.length() == 0)
          throw new IllegalArgumentException("Extension name == null");
      //查找默认扩展实现,也就是@SPI("默认值")
      if ("true".equals(name)) {
          return getDefaultExtension();
      }
      //先查缓存
      Holder holder = cachedInstances.get(name);
      if (holder == null) {
          // 缓存不存在就创建
          cachedInstances.putIfAbsent(name, new Holder());
          holder = cachedInstances.get(name);
      }
      Object instance = holder.get();
      if (instance == null) {
          // holder的意义就是用来上锁
          synchronized (holder) {
              instance = holder.get();
              if (instance == null) {
                  // 真实创建具体实现类逻辑
                  instance = createExtension(name);
                  // 放入缓存
                  holder.set(instance);
              }
          }
      }
      return (T) instance;
    }
    
  • private T createExtension(String name)

    /**
     * 创建扩展类实例
     */
    private T createExtension(String name) {
      //获得对应的具体实现类,getExtensionClasses 扫描 META-INF/dubbo/internal/、META-INF/dubbo/、META-INF/services/文件夹查找扩展配置
      Class clazz = getExtensionClasses().get(name);
      if (clazz == null) {
          throw findException(name);
      }
      try {
          // 现看缓存
          T instance = (T) EXTENSION_INSTANCES.get(clazz);
          if (instance == null) {
              // 缓存不存在就创建
              EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
              instance = (T) EXTENSION_INSTANCES.get(clazz);
          }
          // 自动注入依赖的其他扩展类
          injectExtension(instance);
          // 自动包装,用 Wrapper 类包装,循环层层嵌套包装
          Set> wrapperClasses = cachedWrapperClasses;
          if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
              for (Class wrapperClass : wrapperClasses) {
                  instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
              }
          }
          return instance;
      } catch (Throwable t) {
          throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                  type + ")  could not be instantiated: " + t.getMessage(), t);
      }
    }
  • private Map> loadExtensionClasses()

    /**
     * 从三个配置文件夹中扫描当前 ExtensionLoader 实例对应的接口类的实现类配置
     */
    private Map> loadExtensionClasses() {
      final SPI defaultAnnotation = type.getAnnotation(SPI.class);
      if (defaultAnnotation != null) {
          //@SPI内的默认值
          String value = defaultAnnotation.value();
          if ((value = value.trim()).length() > 0) {
              String[] names = NAME_SEPARATOR.split(value);
              //只允许有一个默认值
              if (names.length > 1) {
                  throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                          + ": " + Arrays.toString(names));
              }
              if (names.length == 1) cachedDefaultName = names[0];
          }
      }
      // 扫描3个文件夹
      Map> extensionClasses = new HashMap>();
      loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
      loadDirectory(extensionClasses, DUBBO_DIRECTORY);
      loadDirectory(extensionClasses, SERVICES_DIRECTORY);
      return extensionClasses;
    }
  • private void loadDirectory(Map> extensionClasses, String dir)

    /**
     * 扫描一个文件夹获取其中的接口实现类配置
     */
    private void loadDirectory(Map> extensionClasses, String dir) {
      // 拼接文件名
      String fileName = dir + type.getName();
      try {
          Enumeration urls;
          // 用当前 ExtensionLoader 的 classloader 扫描加载扩展实现类配置
          ClassLoader classLoader = findClassLoader();
          if (classLoader != null) {
              urls = classLoader.getResources(fileName);
          } else {
              urls = ClassLoader.getSystemResources(fileName);
          }
          if (urls != null) {
              //遍历每个文件
              while (urls.hasMoreElements()) {
                  java.net.URL resourceURL = urls.nextElement();
                  // 解析文件内容,加载对应的扩展类,就不展开讲了,比较简单
                  loadResource(extensionClasses, classLoader, resourceURL);
              }
          }
      } catch (Throwable t) {
          logger.error("Exception when load extension class(interface: " +
                  type + ", description file: " + fileName + ").", t);
      }
    }
  • private T injectExtension(T instance)

    /**
     * 如果当前扩展类实例依赖了其他的扩展类则用setter方法注入对应的实例
     */
    private T injectExtension(T instance) {
      try {
          if (objectFactory != null) {
              //反射获得该类的所有方法
              for (Method method : instance.getClass().getMethods()) {
                  //是set方法且只有一个参数且声明为public
                  if (method.getName().startsWith("set")
                          && method.getParameterTypes().length == 1
                          && Modifier.isPublic(method.getModifiers())) {
                      // 是否禁止了自动注入
                      if (method.getAnnotation(DisableInject.class) != null) {
                          continue;
                      }
                      Class pt = method.getParameterTypes()[0];
                      try {
                          // 截取 setter 方法的后半部分作为属性名称 比如:setProtocol 截取出来是 protocol
                          String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                          // 调用 objectFactory 尝试获取扩展实例
                          Object object = objectFactory.getExtension(pt, property);
                          if (object != null) {
                              // 调用反射注入属性
                              method.invoke(instance, object);
                          }
                      } catch (Exception e) {
                          logger.error("fail to inject via method " + method.getName()
                                  + " of interface " + type.getName() + ": " + e.getMessage(), e);
                      }
                  }
              }
          }
      } catch (Exception e) {
          logger.error(e.getMessage(), e);
      }
      return instance;
    }
  • public T getAdaptiveExtension()

    /**
     * 获取一个自适应扩展实例,该实例本身并不实现扩展接口,会在运行时动态从url中获取实现类的name再加载对应的实现类返回
     */
    public T getAdaptiveExtension() {
      // 先查缓存
      Object instance = cachedAdaptiveInstance.get();
      if (instance == null) {
          // 是否曾经创建过失败了
          if (createAdaptiveInstanceError == null) {
              synchronized (cachedAdaptiveInstance) {
                  instance = cachedAdaptiveInstance.get();
                  if (instance == null) {
                      try {
                          //创建适配器对象
                          instance = createAdaptiveExtension();
                          cachedAdaptiveInstance.set(instance);
                      } catch (Throwable t) {
                          createAdaptiveInstanceError = t;
                          throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
                      }
                  }
              }
          } else {
              throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
          }
      }
    
      return (T) instance;
    }
  • private Class getAdaptiveExtensionClass()

    /**
     * 获取适配器类,每个含有@Adaptive注解的类或方法都会有这个类,这个类是字节码动态生成的,
     * 例:com.alibaba.dubbo.rpc.cluster.Cluster$Adaptive
     */
    private Class getAdaptiveExtensionClass() {
      // 确定扫描过了SPI配置文件
      getExtensionClasses();
      // 先查缓存,这里注意如果当前接口有实现类被 @Adaptive 注解标记了则会扫描时放进缓存,不会走字节码生成过程
      // 如:AdaptiveCompiler
      if (cachedAdaptiveClass != null) {
          return cachedAdaptiveClass;
      }
      // 动态生成适配器类
      return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
  • private Class createAdaptiveExtensionClass()

    /**
     * 用编译器生成适配类的代码并加载该类
     */
    private Class createAdaptiveExtensionClass() {
      //生成适配器类源代码
      String code = createAdaptiveExtensionClassCode();
      ClassLoader classLoader = findClassLoader();
      // 这里相当于递归调用了 getAdaptiveExtension,但由于 Compiler 有静态实现类 AdaptiveCompiler ,不会走到这里来,所以不会出现无限递归
      com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
      //编译并加载
      return compiler.compile(code, classLoader);
    }
  • public List getActivateExtension(URL url, String key) 获取无条件加载的扩展实现类,即用了Activate注解且注解中group参数未设置的扩展类
  • public List getActivateExtension(URL url, String key, String group) 获取有加载条件的扩展实现类,即用了Activate注解且注解中group参数不为空的扩展类
  • public List getActivateExtension(URL url, String[] values, String group) 上边两个方法都是调用改方法实现的
    该方法会将多个扩展类根据用户配置的内容进行增减及排序,典型场景: 过滤器,排序是用 ActivateComparator 来实现的
  • 你可能感兴趣的:(javadubbo后端)