Java SPI + Dubbo SPI

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Java_HuiLong/article/details/83513155

SPI-Service Provider Interface : 服务提供接口

Java SPI + Dubbo SPI

Java SPI + Dubbo SPI 的区别

Java SPI

1.简单的总结下java spi机制的思想

我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。
java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要

2.SPI具体约定

java spi的具体约定为:当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。
该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,
并装载实例化,完成模块的注入。 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。
jdk提供服务实现查找的一个工具类:java.util.ServiceLoader

3.缺点

虽然ServiceLoader也算是使用的延迟加载,但是基本只能通过遍历全部获取,也就是接口的实现类全部加载并实例化一遍。如果你并不想用某些实现类,它也被加载并实例化了,这就造成了浪费。获取某个实现类的方式不够灵活,只能通过Iterator形式获取,不能根据某个参数来获取对应的实现类

Dubbo SPI

具体还是要看下dubbo源码,这个是我看过源码之后理的逻辑图:

在这里插入图片描述

dubbo的扩展机制

  1. 简单功能介绍

dubbo的扩展机制和java的SPI机制非常相似,但是又增加了如下功能:
1 可以方便的获取某一个想要的扩展实现,java的SPI机制就没有提供这样的功能
2 对于扩展实现IOC依赖注入功能:
举例来说:接口A,实现者A1、A2。接口B,实现者B1、B2。
现在实现者A1含有setB()方法,会自动注入一个接口B的实现者,此时注入B1还是B2呢?都不是,而是注入一个动态生成的接口B的实现者B$Adpative,该实现者能够根据参数的不同,自动引用B1或者B2来完成相应的功能
3 对扩展采用装饰器模式进行功能增强,类似AOP实现的功能
还是以上面的例子,接口A的另一个实现者AWrapper1。大体内容如下:
private A a;
AWrapper1(A a){
this.a=a;
}
因此,我们在获取某一个接口A的实现者A1的时候,已经自动被AWrapper1包装了。

2 . dubbo的ExtensionLoader解析扩展过程

对于一个接口的实现者,ExtensionLoader分三种情况来分别存储对应的实现者,属性分别如下:

  1. Class<?> cachedAdaptiveClass;//自适配对象

  2. Set<Class<?>> cachedWrapperClasses;//包含接口类的构造方法,wrapper对象

  3. Holder<Map<String, Class<?>>> cachedClasses;//

    情况1: 如果这个class含有@Adaptive注解,则将这个class设置为Class<?> cachedAdaptiveClass。

      /**
      * 缓存的自适应拓展对象的类
      *
      * {@link #getAdaptiveExtensionClass()}
      */
     private volatile Class<?> cachedAdaptiveClass = null;
    

    情况2: 如果类实现没有打上@Adaptive,尝试获取带对应接口参数的构造器,如果能够获取到,则说明这个class是一个装饰类即,需要存到Set<Class<?>> cachedWrapperClasses中

     /**
      * 拓展 Wrapper 实现类集合
      *
      * 带唯一参数为拓展接口的构造方法的实现类
      *
      * 通过 {@link #loadExtensionClasses} 加载
      */
     private Set<Class<?>> cachedWrapperClasses;
    

    情况3: 如果没有上述构造器。则获取class上的Extension注解,根据该注解的定义的name作为key,存至Holder<Map<String, Class<?>>> cachedClasses结构中

     /**
      * 缓存的拓展实现类集合。
      *
      * 不包含如下两种类型:
      *  1. 自适应拓展实现类。例如 AdaptiveExtensionFactory
      *  2. 带唯一参数为拓展接口的构造方法的实现类,或者说拓展 Wrapper 实现类。例如,ProtocolFilterWrapper 。
      *     拓展 Wrapper 实现类,会添加到 {@link #cachedWrapperClasses} 中
      *
      * 通过 {@link #loadExtensionClasses} 加载
      */
     private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
    

猜你喜欢

转载自blog.csdn.net/Java_HuiLong/article/details/83513155