jdk的SPI和dubbo的SPI

什么是SPI:

     SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。 SPI的作用就是为这些被扩展的API寻找服务实现。使用SPI机制的优势是实现解耦,使得第三方服务模块的装配控制逻辑与调用者的业务代码分离。

JDK中的SPI:

java中如果想要使用SPI功能,先要提供标准的服务接口,然后再提供相关接口实现和服务调用者。通过SPI机制中约定的信息进行查询相应接口的实现,如下图:

SPI遵循的约定如下:

  1. 当服务提供者提供了一个接口的一种具体实现后,在META-INF/services 目录下创建一个以 “接口全限定名” 为命名的文件,内容为实现类的权限定名
  2. 接口实现类所在的jar包,放在主程序的classpath中
  3. 主程序通过 java.util.ServiceLoader 动态加载实现模块,它通过扫描META-INF/services 目录下的配置文件找到实现类的全限定名,把类加载到JVM
  4. SPI的实现类必须要有一个无参构造

JDK的SPI示例:

1、创建一个maven项目,用来存放服务接口:

2、在创建一个maven项目,用来实现上面创建的接口,这里的pom文件需要依赖上面创建的接口maven工程

创建完接口,下一步开始编写配置文件:

  1. 创建 META-INF/services 目录
  2.  在该目录下创建与接口的权限定名项目的文件: cn.zsm.spi.HelloSPI
  3. 配置文件的内容是任意接口的实现类的全限定名,可以写其中某一个或某几个。这里我两个都写了进去,如下图:

 

3、新建一个maven工程,用于测试SPI功能:

    public static void main(String[] args) {
        ServiceLoader<HelloSPI> load = ServiceLoader.load(HelloSPI.class);

        for(HelloSPI helloSPI : load){
            System.out.println(helloSPI.getClass().getName() + " , result is : "+helloSPI.helloSPI());
        }
    }

输出结果: 

SPI源码简单介绍:

从上面SPI示例中可以看出,JSK的SPI功能的关键是ServiceLoader,下面我们简单介绍一下ServiceLoader的工作过程:

有兴趣的同学可以拔一下JDK中的源码,因为源码比较长,这里就不再赘述。

 

Dubbo中的SPI:

dubbo中使用了大量的SPI来作为扩展点,通过实现统一接口的前提下,可以进行定制自己的实现类。常见的有potocol协议、负载均衡算法等都可以通过SPI的方式进行定制化。后面我们讲述源码的时候会有涉及。

java的spi机制有着如下的弊端:

  • 只能遍历所有的实现,并全部实例化。
  • 配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。
  • 扩展如果依赖其他的扩展,做不到自动注入和装配。
  • 扩展很难和其他的框架集成,比如扩展里面依赖了一个Spring bean,原生的Java SPI不支持。

 dubbo的spi有如下几个概念:

  •     扩展点:一个接口。
  •     扩展:扩展(接口)的实现。
  •     扩展自适应实例:其实就是一个Extension的代理,它实现了扩展点接口。在调用扩展点的接口方法时,会根据实际的参数来决定要使用哪个扩展。dubbo会根据接口中的参数,自动地决定选择哪个实现。
  •     @SPI:该注解作用于扩展点的接口上,表明该接口是一个扩展点。
  •     @Adaptive:@Adaptive注解用在扩展接口的方法上。表示该方法是一个自适应方法。Dubbo在为扩展点生成自适应实例时,如果方法有@Adaptive注解,会为该方法生成对应的代码。

总结一下,dubbo的SPI实现与JDK的实现有一下几点不同:

  1.  pom文件需要引入dubbo
  2. dubbo的SPI服务的接口需要有 @SPI注解
  3. 接口可以用@Adaptive注解标识自适应方法, 并可以选择要使用的扩展点
  4. 配置文件的路径是: META-INF/dubbo
  5. 配置文件中的内容,除了有接口的实现类的全限定名外,每个实现类还要指定一个KEY
  6. SPI服务获取,使用ExtensionLoader.getExtensionLoader(****.class)  方法

 

dubbo的Adaptive功能,主要解决的问题是如何动态选择具体的扩展点。通过getAdaptiveExtension 统一对指定的接口对应的所有扩展点进行封装,通过URL 的方式对扩展点进行动态选择(dubbo中所有的注册信息都是通过URL的形式处理的)。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值