回答
在 JDBC 4.0之后使用spi机制才会破坏双亲委派机制。
java.sql.DriverManager
在初始化时会调用 ServiceLoader 的 load()
去加载实现了java.sql.Driver
接口的实现类。ServiceLoader 会搜索当前类路径上所有JAR文件内的META-INF/services/java.sql.Driver
文件,从这些文件中读取实现类的全限定名。假如我们加载到了 MySQL 的驱动程序,获取的实现类为 com.mysql.jdbc.Driver
,但是 DriverManager
位于 rt.jar
包,类加载器是启动类加载器,而 com.mysql.jdbc.Driver
位于 MySQL 驱动程序的 jar 文件中,启动类加载器是无法加载该类的,那怎么办呢?
添加一个线程上下文类加载器(Thread Context ClassLoader),在启动类加载器中获取应用程序类加载器。有了线程上下文类加载器,应用程序就可以把原本需要由启动类加载器进行加载的类,改为由应用程序类加载器来加载了,从而打破双亲委派模型。
详情
原生 JDBC 中的 Driver 驱动仅仅只是一个接口,具体的实现有不同的数据库厂商来提供,例如 MySQL 数据库提供的 com.mysql.cj.jdbc.Driver
。
DriverManager 是一个管理 JDBC 驱动的类,它主要提供两个功能:
- 驱动注册:当 JDBC 驱动类被加载到JVM时,它应该调用
DriverManager.registerDriver()
将自身注册到 DriverManager 中。 - 管理连接:调用
DriverManager.getConnection(url, user, password)
可以获取与数据库的连接。这个方法会检查已注册的驱动,找到能够处理提供的URL的合适驱动,并通过该驱动建立连接。