SPI 全称为 Service Provider Interface,是一种java提供的“服务发现”机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能;

使用时需要遵循其规范,我们先看下面的列子

 

 

 在 classpath 路径下 新建目录 /META_INF/services  文件命名为 接口 全类名(‘com.me.services.PrintServices’)

 文件内容 为接口实现的全类名

 

 使用 ServiceLoader 进行服务加载发现

 运行结果如下

 

 源码解析:

 在 调用 printerServices.iterator() 方法时 会返回一个迭代器,当我们调用 serviceIterator.next()方法时 调用的便是该迭代器的next()方法

进一步看 调用了 nextService()

 

我们看一下 nextServics()方法

 

那 hasNextServices()方法做了什么

 注: 图上的  静态变量PREFIX画错了, 应该是 PREFIX = "META-INF/services/"

这就是为什么最开始 我们为什么在 classpath下 新建 /META-INF/services 目录 并且以 接口类路径命名文件的原因 

 

 使用场景:

  1. 根据使用需求,动态替换不同服务实现

  2. 数据库驱动 java.sql.Driver 就是很经典的SPI使用案例,不同数据库服务提供者遵循该规范; 作为使用方,引入哪一方的驱动 则运行时启动该方的驱动

  3. dubbo 中也有大量的spi应用

 

posted on 2020-04-22 10:25  yang希军  阅读(190)  评论(0)    收藏  举报