1. 1. 何谓SPI?
  2. 2. SPI和API有什么区别
  3. 3. 浅析原理
  4. 4. ServiceLoader

何谓SPI?

SPI 即Service Provider Interface,服务提供者的接口,专门提供给服务提供者或者框架功能的开发者去使用的一个接口。很多框架都使用到了SPI,数据库加载驱动、日志接口等

SPI和API有什么区别

  • SPI 中的接口,是服务调用方设计接口规则,由实现方去实现接口。比如日志面板slf4j,具体日志框架是logback、log4j还是log4j2并不关心,slf4j设计的接口规则,由具体日志框架去实现即可
  • API中的接口,是服务提供方设计并且实现的,一般前后端或者微服务之间调用的就是API。

image-20260122225919112

浅析原理

其实SPI中最重要的是其中两个服务,一个是接口调用方(Slf4j),一个是接口实现方(logback)。下面举例slf4j和logbak的SPI实现原理

  1. Slf4j作为日志门面,规范了日志的实现规则,日志框架需要按照此规则才能接入slf4j日志门面。
    https://github.com/qos-ch/slf4j/blob/master/slf4j-api/src/main/java/org/slf4j/spi/SLF4JServiceProvider.java
    在该项目中,可以看到其中org.slf4j.spi.SLF4JServiceProvider 为制定的接口规则:

image-20260122230330799

  1. logbak作为日志框架,需要接入slf4j日志门面,就需要实现slf4j制定的接口规范。

    • 需要在META-INF的service目录下,新建一个slf4j待实现接口的目录,并且内容为logback框架实现接口的文件路径:
      image-20260122230553035

    • 可以看到logback对其接口进行了实现:

      image-20260122230648444

ServiceLoader

如上原理,当使用slf4j的时候,他怎么知道该使用logback还是log4j还是log4j2 ? 最关键的就是有一个服务调用方加载实现方的地方:ServiceLoader

image-20260122231051427

调用方主要的流程就是:

  1. 通过 URL 工具类从 jar 包的 /META-INF/services 目录下面找到对应的文件,
  2. 读取这个文件的名称找到对应的 spi 接口,
  3. 通过 InputStream 流将文件里面的具体实现类的全类名读取出来,
  4. 根据获取到的全类名,先判断跟 spi 接口是否为同一类型,如果是的,那么就通过反射的机制构造对应的实例对象,
  5. 将构造出来的实例对象添加到 Providers 的列表中。