class.forName 里面都发生了啥?一文搞懂 Spi 机制

时间:2024-01-20 22:55:19



一文搞懂 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

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_驱动扩展

仿照 Java.sql.DriverManager 源码,编写我们自己的 DriverManager 类,当 DriverManager 实例化的时候,静态代码块会被调用,执行我们的 loadInitialDrivers 方法(去加载驱动),至于加载哪些驱动,里面会去扫描 ClassPath 路径下的 META-INF/services 里面的文件,实例化所有com.example.zzh.spi.java.sql.Driver 的接口实现类,这些实现类交付给各大驱动厂商扩展例如:Oracle 驱动、Mysql 驱动等。接下来看下驱动厂商是如何做的

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_加载_02

Mysql 驱动厂商

看源码包,就是在 ClassPath 路径下的 META-INF/services 文件夹下面创建了一个 java.sql.Driver 文件,ok 咱们一比一仿制就行。

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_Spi 机制_03


按照同样的目录结构创建 com.example.zzh.spi.java.sql.Driver 文件,然后文件里面指定 com.example.zzh.spi.java.sql.Driver 的实现类就行。

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_驱动扩展_04


MysqlDriver 类代码如下,通过加载静态代码块的方式加载驱动。这样依赖驱动就被加载到了标准服务厂那了。

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_驱动扩展_05

????????文件名定义规范请查阅 Spi 如何使用章节????????

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_java_06

扩展驱动加载测试

由于用的 Spring Boot ,在启动类里面显示的调用一下 DriverManager 。触发 DriverManager 类中的静态代码块中的逻辑。

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_加载_07


可以看到在项目启动之初我们自己的驱动程序就被加载了。后续我们想用 Oracle 驱动的时候,引入 Oracle 的包就行。

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_插件开发_08


截个图 Oracle 的驱动包也是利用 Spi 扩展的。

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_加载_09

Spi 机制其他应用场景

Spring Boot 自动装配也是用到了 Spi 机制。
手把手debug自动装配源码、顺带弄懂了@Import等相关的源码(全文3w字、超详细)

可能遇到的问题(Spi 失效)

如果你用到的是 Spring Boot,但是加载不到我们的 Spi 配置文件,不妨看看编译包里面是否包含我们的 META-INF文件

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_驱动扩展_10


没包含的话配置一下 resources 加载的资源范围就行

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_插件开发_11

结语

我是小咸鱼 ,会在以后的日子里跟大家一起学习,一起进步! 觉得文章不错的话,可以关注我,这样就不会错过很多技术干货啦~

????????微信公众号刚刚起步,后续创作更多精品内容提供给大家

class.forName() 里面都发生了啥?一文搞懂 Spi 机制_加载_12