一文搞懂 Spi 机制
- 前言
- class.forName() 里面都发生了啥?
- Spi 是什么?
- Spi 如何使用?
- Spi 代码实现(标准服务厂商)
- Mysql 驱动厂商
- 扩展驱动加载测试
- Spi 机制其他应用场景
- 可能遇到的问题(Spi 失效)
- 结语
前言
左眼用来忘记你,右眼用来回忆你,不是我不爱你,只是哥一直在你心里,大家好我是一只摆烂的小咸鱼,今天给大家介绍 Java Spi 机制原理,以及 Spi 机制在我们身边的应用场景。
class.forName() 里面都发生了啥?
答:显示加载数据库驱动
Spi 是什么?
答:Spi 是 Jdk 内置的服务动态发现替换的机制,一种解耦的思想。
Spi 如何使用?
答:在 ClassPath 路径下的 META-INF/services 文件夹创建这么一个文件,
以接口的全限定名来命名文件名,文件里面写该接口的实现名。然后通过调用
ServiceLoader.load(限定接口),即可加载到所有接口实现类。这个实现类可以由多个服务商提供,但是客户只需调用标准服务接口即可。当客户想替换服务商时,替换实现类即可。而这个实现类由每个服务商维护,完全不用客户操心。客户只管用就行。代码耦合性很低。
Spi 代码实现(标准服务厂商)
手撕一遍源码加深理解,就拿最常用的 com.mysql.cj.jdbc.Driver 驱动是如何被加载的举例,仿照 Java.sql.Driver 源码,编写我们自己的标准驱动接口 com.example.zzh.spi.java.sql.Driver
仿照 Java.sql.DriverManager 源码,编写我们自己的 DriverManager 类,当 DriverManager 实例化的时候,静态代码块会被调用,执行我们的 loadInitialDrivers 方法(去加载驱动),至于加载哪些驱动,里面会去扫描 ClassPath 路径下的 META-INF/services 里面的文件,实例化所有com.example.zzh.spi.java.sql.Driver 的接口实现类,这些实现类交付给各大驱动厂商扩展例如:Oracle 驱动、Mysql 驱动等。接下来看下驱动厂商是如何做的
Mysql 驱动厂商
看源码包,就是在 ClassPath 路径下的 META-INF/services 文件夹下面创建了一个 java.sql.Driver 文件,ok 咱们一比一仿制就行。
按照同样的目录结构创建 com.example.zzh.spi.java.sql.Driver 文件,然后文件里面指定 com.example.zzh.spi.java.sql.Driver 的实现类就行。
MysqlDriver 类代码如下,通过加载静态代码块的方式加载驱动。这样依赖驱动就被加载到了标准服务厂那了。
????????文件名定义规范请查阅 Spi 如何使用章节????????
扩展驱动加载测试
由于用的 Spring Boot ,在启动类里面显示的调用一下 DriverManager 。触发 DriverManager 类中的静态代码块中的逻辑。
可以看到在项目启动之初我们自己的驱动程序就被加载了。后续我们想用 Oracle 驱动的时候,引入 Oracle 的包就行。
截个图 Oracle 的驱动包也是利用 Spi 扩展的。
Spi 机制其他应用场景
Spring Boot 自动装配也是用到了 Spi 机制。
手把手debug自动装配源码、顺带弄懂了@Import等相关的源码(全文3w字、超详细)
可能遇到的问题(Spi 失效)
如果你用到的是 Spring Boot,但是加载不到我们的 Spi 配置文件,不妨看看编译包里面是否包含我们的 META-INF文件
没包含的话配置一下 resources 加载的资源范围就行
结语
我是小咸鱼 ,会在以后的日子里跟大家一起学习,一起进步! 觉得文章不错的话,可以关注我,这样就不会错过很多技术干货啦~
????????微信公众号刚刚起步,后续创作更多精品内容提供给大家