概要

SPI全称是service Provider Interface. 大多数开发人员可能不熟悉,因为这个机制是针对第三方厂商或者插件来提供服务的。SPI机制是JDK中java.util.ServiceLoader提供的,后面我们会详细介绍。

一般我们在做开发的时候,都是抽象各个模块,然后有很多的实现方案,比如日志模块、xml解析模块、JDBC模块等。在面向对象设计里,我们一般推荐模块之间最好是基于接口编程,而不对具体的实现进行硬编码。因为一旦代码改动涉及到具体的实现类,就违反了可插拔的原则。为了实现模块装配的时候不在程序里动态指明,就需要一种服务发现机制。而Java SPI就提供了这样的一种机制:为某个接口寻找服务实现的机制。这个有点类似与IOC的思想,就是将装配的控制权移交到程序之外

什么是SPI

SPI是JDK内置的一种服务提供发现机制。目前市面上有很多框架都是用它来做服务的扩展发现。简单来说,它是一种动态替换发现的机制。举个简单的例子,我们想在运行时动态给它添加实现,你只需要添加一个实现,然后把新的实现描述给JDK知道就行了。

实现SPI需要遵循的标准

我们如何去实现一个标准的SPI发现机制呢?其实很简单,只需要满足以下提交就行了

  1. 需要在classpath下创建一个目录,该目录命名必须是:META-INF/service

  2. 在该目录下创建一个properties文件,该文件需要满足以下几个条件

    代码说明

    我们定义了一个接口叫IHelloService, 接口中有一个方法

    spi用在什么地方?你懂什么是SPI吗(1)

    接着定义了两个实现类,一个是通过文本的方式来问候,另一个是通过表情的方式来问候,我们来看一下这两个实现类的代码:

    spi用在什么地方?你懂什么是SPI吗(2)

    以上就是核心代码了,接着来看一下resources目录下的文件,按照上面第二点说的要实现SPI需要满足的格式:

    1. resources/META-INF/service。

    2. 文件名要以扩展接口的全路径名:com.gupao.spi.demo.hello.IHelloService.properties

    3. 该文件的内容如下

    spi用在什么地方?你懂什么是SPI吗(3)

    这样就实现了一个简单的SPI的实现

    SPI的实际应用

    其实SPI在很多地方有应用,可能大家都没有关注,最常用的就是JDBC驱动,我们来看看是怎么应用的

    JDK本身提供了数据访问的api。在java.sql这个包里面

    我们在连接数据库的时候,一定需要用到java.sql.Driver这个接口对吧。然后我好奇的去看了下java.sql.Driver的源码,发现Driver并没有实现,而是提供了一套标准的api接口。大家有兴趣可以去看看

    因为我们在实际应用中用的比较多的是mysql,所以我去mysql的包里面看到一个如下的目录结构

    spi用在什么地方?你懂什么是SPI吗(4)

    看到了吗? 目录结构是不是符合SPI的定义?我怀着好奇心,打开了java.sql.Driver这个文件

    spi用在什么地方?你懂什么是SPI吗(5)

    这个文件里面写的就是mysql的驱动实现。我恍然大悟,原来通过SPI机制把java.sql.Driver和mysql的驱动做了集成。这样就达到了各个数据库厂商自己去实现数据库连接,jdk本身不关心你怎么实现。

    SPI的缺点

    1. JDK标准的SPI会一次性加载实例化扩展点的所有实现,什么意思呢?就是如果你在META-INF/service下的文件里面加了N个实现类,那么JDK启动的时候都会一次性全部加载。那么如果有的扩展点实现初始化很耗时或者如果有些实现类并没有用到,那么会很浪费资源

    2. 如果扩展点加载失败,会导致调用方报错,而且这个错误很难定位到是这个原因

    度娘搜索【咕泡学院】获取更多技术资料和视频下载。

    往期(JVM、多线程、分布式、高并发、高可用、nginx、redis、mysql、zookeeper、dubbo等)免费公开课关注咕泡学院即可获得,点击关注

    spi用在什么地方?你懂什么是SPI吗(6)

    ,