JAVA SPI(service provider interface)

SPI全称(service provider interface),是JDK内置的一种服务提供发现机制,目前市面上有很多框架都是用它来做服务的扩展发现,大家耳熟能详的如JDBC、日志框架都有用到;简单来说,它是一种动态替换发现的机制。举个简单的例子,如果我们定义了一个规范,需要第三方厂商去实现,那么对于我们应用方来说,只需要集成对应厂商的插件,既可以完成对应规范的实现机制。 形成一种插拔式的扩展手段。

实现一个SPI

根据上文描述,我们首先需要定义一个接口,然后第三方尝尝去做各自的实现。我们这里定义个DBDriver接口,然后完成两种实现,具体操作如下。
1、IDEA中创建一个Maven工程 spi-parent 。下建四个模块
DBDriver 定义接口 DBDriver
Mysql 实现接口方法 模拟厂商实现
oracle 实现接口方法 模拟厂商实现
spiload 加载厂商实现测试
创建好后项目结构如下:
在这里插入图片描述
2、DBDriver中定义一个接口 。
在这里插入图片描述
3、MySql 和 oracle pom.xml 中 增加对 DBDriver的依赖 并分别实现 DBDriver接口,以Mysql为例
pom.xml 中增加对DBDriver 模块的依赖在这里插入图片描述增加实现类 MySqlDriver 实现 DBDriver 接口及其方法,如下:
在这里插入图片描述
增加java目录下 增加 resources/META-INF/services/ 目录 在该目录下创建文件 com.test.spi.DBDriver(实现的接口全名),文件的内容为 com.test.spi.MySqlDriver (实现类的全名) 如下:
在这里插入图片描述
如此DBDriver 的 mysql实现完成。
按照同样的步骤 完成 oralce 实现 如下图:
在这里插入图片描述
4、spiload 模块中增加 对增加对上述三个模块的依赖,然后增加测试类App
增加pom.xml中的依赖

 <dependency>
            <groupId>com.test.spi</groupId>
            <artifactId>DBDriver</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.test.spi</groupId>
            <artifactId>MySql</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.test.spi</groupId>
            <artifactId>oracle</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

增加App类 如下:
在这里插入图片描述

运行App.main() 执行结果如下,代码自动找到了 我们的两个 DBDriver 的实现:
在这里插入图片描述

5、看下java.util.ServiceLoader 的源码
1)定义了如下属性,五个属性分别是路径前缀(就是我们放置配置文件的目录)、接口Class类,类加载器 、 一个存放接口实现 提供者的集合 和一个迭代器 。这个类的作用就是 到 指定的目录(META-INF/services/)下去加载所有的实现类放入集合中。
在这里插入图片描述
当遍历提供者时就会 执行 迭代器的 hasNext()方法去到路径下 加载已经配置的实现类,并验证配置是否合法,最后转换成对应的实例保存在集合中。如下图:
在这里插入图片描述

总结:

1、JDKSPI实现方式.
只需按照SPI本身定义的规范来进行配置即可
JDK SPI规范如下:

  1. 需要在classpath下创建一个目录,该目录命名必须是:META-INF/services
  2. 在该目录下创建一个properties文件,该文件需要满足以下几个条件
    a) 文件名必须是扩展的接口的全路径名称
    b) 文件内容是该扩展接口的所有实现类
    c) 文件的编码格式是UTF-8
  3. 通过java.util.ServiceLoader的加载机制来发现

2、SPI的实际应用

SPI在很多地方有应用,大家可以看看最常用的java.sql.Driver驱动。JDK官方提供了java.sql.Driver这个驱动扩展点,但是你们并没有看到JDK中有对应的Driver实现。我们可以看一下 mysql驱动 jar包的结构如下:
在这里插入图片描述
可以看到里边定义了和我们刚才同样的结构和文件。

3、SPI的缺点
JDK标准的SPI会一次性加载实例化扩展点的所有实现,什么意思呢?就是如果你在META-INF/service下的文件里面加了N个实现类,那么JDK启动的时候都会一次性全部加载。那么如果有的扩展点实现初始化很耗时或者如果有些实现类并没有用到,那么会很浪费资源。
Dubbo也有SPI机制规范
大部分的思想都是和SPI是一样,只是下面两个地方有差异。

  1. 需要在resource目录下配置META-INF/dubbo或者META-INF/dubbo/internal或者META-INF/services,并基于SPI接口去创建一个文件
  2. 文件名称和接口名称保持一致,文件内容和SPI有差异,内容是KEY对应Value

猜你喜欢

转载自blog.csdn.net/zhangxm_qz/article/details/86519192
今日推荐