jdk和dubbo的SPI详解

SPI的全名为Service Provider Interface.大多数开发人员可能不熟悉。因为这个是针对厂商或者插件的。简单总结下java spi机制的思想。

我们系统里抽象的各个模块,往往有很多不同的实现方案。比如日志模块的方案,xml解析模块,jdbc模块的方案等。面向对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。

一旦代码里设计具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。

Java spi就是提供这样的一个机制;为某个接口寻找服务实现的机制。有点类似IOC的思想,就是讲装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。

Jdk提供服务实现查找的一个工具类:java.util.ServiceLoader

jdk和dubbo的SPI详解

Jdk的SPI的设计目标:

  1. 面向对象的设计里,模块之间是基于接口编程,模块之间不对实现类进行硬编码。
  2. 一旦代码里涉及具体的实现类,就违反了可插拔的原则,如果需要替换一种实现,就需要修改代码。
  3. 为了实现在模块装配的时候,不在模块里面写死代码,这就需要一种服务发现机制。
  4. Java spi就是提供这样的一种机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是讲装配的控制权转移到代码之外。

Jdk的SPI的具体约定如下:

  1. 当服务的提供者(provider),提供了一个接口多种实现时,一般会在jar包的META-INF/services/目录下,创建该接口的全类名文件。
  2. 该文件里面的内容就是该服务接口的具体实现类的全类名名称。
  3. 当外部加载这个模块的时候,就能通过该jar包META-INF/services/里的配置文件得到具体的实现类名,并加载实例化,完成模块的装配。

Dubbo为什么不采用Jdk的SPI?

  1. Jdk标准的SPI会一次性实例化扩展点的所有实现,如果扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
  2. 增加了对扩展点IOC和AOP的支持,一个扩展点可以直接setter注入其他扩展点。

Dubbo 的SPI有哪些约定?

  1. Spi文件存储路径 在META-INF/dubbo/internal目录下,并且文件名为接口的全路径名,就是=接口的包名+接口名
  2. 每个spi文件里面的格式定义为:扩展名=具体的类名,例如:

dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtoco

dubbo 的SPI:

目的:获取一个实现类的对象。

途径:ExtensionLoader.getExtension(String name)

实现路径:

  1. getExtensionLoader(Class type) 就是为该接口new 一个ExtensionLoader,然后缓存起来。
  2. getAdaptiveExtension() 获取一个扩展装饰类的对象这个类有一个规则,如果它没有一个@Adaptive注解,就动态创建一个装饰类,例如Protocol$Adaptive对象。
jdk和dubbo的SPI详解


分享到:


相關文章: