Java链接MySQL——JDBC对双亲委派模型的破坏

JDBC链接MySQL的代码片段和执行结果

Java15和JDBC 8.0.18


    mysql
    mysql-connector-java
    8.0.18

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来加载。



接下来分析如何破坏双亲委派模型:

  1. AppClassLoader加载我们定义的测试类DriverStudy;
  2. 调用DriverManager.getConnection时,委派给其父加载器PlatformClassLoader加载;
  3. getConnection中尝试去加载第三方依赖的数据库Driver时,我们发现没有使用此方法所在类的加载器PlatformClassLoader(因为类加载机制制约,PlatformClassLoader也无法加载第三方类库),而是通过参数传入了测试类DriverStudy的加载器AppClassLoader,另外if语句的条件判断也保证一旦callerCL为null(证明是BootClassLoader)或为PlatformClassLoader时,会被设置为上下文类加载器。
callerCL = Thread.currentThread().getContextClassLoader()。
  1. 上下文类加载器Debug显示如下为AppClassLoader。上下文类加载器顾名思义典型应用就是被线程设置后加载应用,可通过Thread.setContextClassLoaser()方法设置。


总结一下,PlatformClassLoader加载DriverManager,执行getConnection方法后,会显示的找到PlatformClassLoader的子加载器AppClassLoader去加载第三方的依赖类。父加载器调用子加载器进行类的加载,这里打破了双亲委派模型。

你可能感兴趣的:(Java链接MySQL——JDBC对双亲委派模型的破坏)