Java链接MySQL——JDBC对双亲委派模型的破坏
JDBC链接MySQL的代码片段和执行结果
Java15和JDBC 8.0.18
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
public void driverTest() throws SQLException {
System.out.println(java.sql.Driver.class.getClassLoader());
System.out.println(java.sql.DriverManager.class.getClassLoader());
System.out.println(com.mysql.jdbc.Driver.class.getClassLoader());
Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306", "root", "123456");
}
System.out.println打印的结果
jdk.internal.loader.ClassLoaders$PlatformClassLoader@48140564
jdk.internal.loader.ClassLoaders$PlatformClassLoader@48140564
jdk.internal.loader.ClassLoaders$AppClassLoader@55054057
上面System.out.println打印的结果很容易理解,com.mysql.jdbc.Driver是第三方提供的依赖由AppClassLoader加载,其父类java.sql.Driver是JDK自带模块被PlatformClassLoader加载。java.sql.DriverManage与java.sql.Driver相同。
注:JDK9之后用PlatformClassLoader代替ExtClassLoader加载器,用来加载JDK中的非核心模块类。
如何破坏双亲委派模型
深入DriverManager.getConnection源码
getConnection源码
Debug代码,其中参数caller结果如下,是我们自定义调用DriverManager.getConnection的方法driverTest()的类。而这个自定义类的ClassLoader显然是AppClassLoader。
那么,继续往下执行时,callerCL会被赋值为AppClassLoader。if语句不会走到,之后注册的所有数据库Driver都是基于callerCL来加载。
接下来分析如何破坏双亲委派模型:
- AppClassLoader加载我们定义的测试类DriverStudy;
- 调用DriverManager.getConnection时,委派给其父加载器PlatformClassLoader加载;
- getConnection中尝试去加载第三方依赖的数据库Driver时,我们发现没有使用此方法所在类的加载器PlatformClassLoader(因为类加载机制制约,PlatformClassLoader也无法加载第三方类库),而是通过参数传入了测试类DriverStudy的加载器AppClassLoader,另外if语句的条件判断也保证一旦callerCL为null(证明是BootClassLoader)或为PlatformClassLoader时,会被设置为上下文类加载器。
callerCL = Thread.currentThread().getContextClassLoader()。
-
上下文类加载器Debug显示如下为AppClassLoader。上下文类加载器顾名思义典型应用就是被线程设置后加载应用,可通过Thread.setContextClassLoaser()方法设置。
总结一下,PlatformClassLoader加载DriverManager,执行getConnection方法后,会显示的找到PlatformClassLoader的子加载器AppClassLoader去加载第三方的依赖类。父加载器调用子加载器进行类的加载,这里打破了双亲委派模型。