目录
SPI
SPI
SPI全程为ServiceProviderInterface
即服务提供者接口
从java6开始引入的 基于ClassLoader来发现并加载服务的机制
SPI构成组件
-
Service
一个公开的接口或抽象类 定义了一个抽象的功能模块
-
ServiceProvider 服务提供者
service接口的一个实现类
-
ServiceLoader 服务加载者
SPI机制中的核心组件 负责在运行时发现并加载ServiceProvider
SPI执行流程
-
调用serviceLoader的load方法 加载provider
-
在第三方jar包中 可能有多个provider 都实现了此Service接口
最终load方法以接口形式返回service -
application只需要与service接口交互 不需要关心具体是那个provider提供了此接口的实现
SPI的作用
SPI在jdbc中的应用
jdbc是使用java访问数据库的一套api - 对应到前文的service
当操作不同的数据库时需要使用不同的jdbc实现 如操作mysql与操作oracle就需要使用不同的jdbc实现
这些jdbc的实现也就是通常所说的"数据库驱动" - 对应到前文的serviceProvider
我们在使用java操作数据库时 需要加载数据库对应的驱动
在spi出现前 我们常用的加载驱动的方式一般如下:
Class.forName("com.mysql.jdbc.Driver");
//使用forName加载驱动类 此处以mysql数据库驱动为例 若是操作其他数据库 需要加载不同的驱动
jdbc实现类的类名被硬编码在java代码中
为了在将来更换数据库驱动时 不需要更改java代码
我们可以将数据库驱动类名写到配置文件中:
driver-name: com.mysql.jdbc.Driver
但我们依然需要记住数据库驱动类的全限定名
使用起来依然算不上方便
上面问题的解决方法为-配置文件由厂商提供
我们所开发的程序 只需要引入数据库驱动jar包
然后根据事先约定好的路径与格式读取对应的文件 即可获取配置信息 加载数据库驱动
具体实现这一功能的类 对应前文所说的ServiceLoader
javaSPI机制的三大要素
规范的配置文件
-
文件路径: 必须在jar包中的META-INF/service目录下
-
文件名称: service接口的全限定名
-
文件内容: service实现类(即service provider类)的全限定名 如果有多个实现类,那么每个实现类在文件中单独占一行
ServiceProvider类必须具备无参构造方法
- service接口的实现类,即serviceProvider类必须具有无参的默认构造方法
因为随后通过反射技术实例化此provider时是不带参数的
保证能加载到配置文件和ServiceProvider类
-
方式一: 将ServiceProvider的jar包放到classpath中 - 可以通过ClassLoader加载 (最常用的 如用maven引入依赖时)
-
方式二:将jar包安装到jre的扩展目录中
-
方式三:自定义一个ClassLoader
小结
SPI提供了一种组件发现和注册的方式,可以用于实现各种插件或者灵活替换框架所使用的组件
基于面向接口编程,配合配置文件与反射技术,实现模块之间的解耦
在如JDBC 等场景中均有应用
此文章为
https://www.bilibili.com/video/BV1RY4y1v7mN/?spm_id_from=333.788&vd_source=e974e5b422b5e93d638b7ac74272a918视频的学习笔记
感谢原内容作者码场安员外