打破双亲委派模型中提到SPI和JDBC相关内容,那么是如何打破双亲委派模型呢?本文进行一个讲解,在开始讲解之前,我们需要先了解Java中的SPI机制
是什么
SPI 全称Service Provider Interface,是 Java 提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。主要是被框架的开发人员使用,最经典的使用比如 java.sql.Driver 接口,其他不同厂商可以针对同一接口做出不同的实现,MySQL和PostgreSQL都有不同的实现提供给用户,而 Java 的 SPI 机制可以为某个接口寻找服务实现。
Java中SPI机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是解耦。下面提供一张图 帮助大家理解:
如何理解
最经典的还是 java.sql.Driver 接口。
条件允许的话,可以打开idea,根据下面一起操作。查找 MySQL 依赖下 META-INF 包下 service 包下 java.sql.Driver 文件打开,发现此文件中只有com.mysql.cj.jdbc.Driver这一个路径。
双击 Shift 复制此路径,我们找到这个这个类并打开,效果如下:
到此为止,我们可以知道 JDK 会根据 java.sql.Driver 文件中的 com.mysql.cj.jdbc.Driver 实现类名去加载 MySQL 中的这个 Driver 实现类了。那么如何加载呢?这就要说到 JDK 中查找服务的实现的工具类了,这个工具类是 java.util.ServiceLoader
。
具体可以查看类详细注解。这里想说的是,这个 ServiceLoader 类中有一个load()
方法,此方法是关键,正通过这个方法可以加载所有驱动。(到这里整个 SPI 机制已经完结,下面的介绍是进一步解释整个驱动如何被加载。)
其实这整个过程就像切菜一样。我们菜 (MySQL 驱动 Driver 准备完毕) 已经洗好了,刀具( ServiceLoader.load()方法 )也已经准备好了,那么我们少了一个持刀的人啊,那么究竟是谁拿这把刀去"切"菜呢?
我们学习 JDBC 的时候应该还记得几个重要概念,分别为 DriverManager,Connection,Statement,PreparedStatement 和 ResultSet。这几个类与接口关系图如下:
这几个核心 API 作用如下:
通过上述我们可以发现 DriverManager 的作用比较大,可以管理和注册数据库驱动以及能得到数据库连接对象。那么管理和注册是否就是那个操刀的人?我们点开 DriverManager 类来看,在此类中快捷键 Ctrl+F12,我们会发现,这个类中有许多方法以及一个静态类初始化器(也就是我们说的静态代码块),回想一下静态代码块有什么作用?什么时候加载?静态代码块中内容如下:
翻译过来就是通过检查系统属性 jdbc.properties 来加载初始 JDBC 驱动程序,然后使用 {@code ServiceLoader} 机制。到这里我们就全都明白了,初始化 DriverManager 类时,也会执行静态代码块中的内容,而静态代码块中的内容主要就是使用 ServiceLoader.load 方法去加载所有的驱动。到此为止,整个SPI机制以及如何加载驱动就已经完结,下一篇继续讲解加载驱动时到底是如何打破双亲委派机制
参考链接
https://zhuanlan.zhihu.com/p/84337883
https://blog.csdn.net/weixin_47267628/article/details/121735098
https://www.cnblogs.com/yougewe/p/12460685.html