You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何有书籍称JDBC破坏双亲委派模型?源码核查未发现相关依据

JDBC与双亲委派模型:为什么资料说破坏但你看到的都是AppClassLoader加载?

Hey there, let's clear up this confusion step by step! It's totally normal to feel confused when the books say one thing but your code inspection shows another—let's break down the history and the current implementation:

1. 历史上的JDBC确实破坏了双亲委派模型

早期JDBC的设计里,DriverManager类是放在rt.jar中的,由Bootstrap ClassLoader(启动类加载器)负责加载。而各个数据库厂商的Driver实现类(比如MySQL的com.mysql.cj.jdbc.Driver)则是放在应用的类路径下,属于Application ClassLoader(应用类加载器)的加载范围。

按照双亲委派模型的规则,父加载器(Bootstrap)会优先尝试加载类,只有当父加载器加载失败时,才会交给子加载器(Application)加载。但这里的问题是:Bootstrap ClassLoader根本无法加载应用类路径下的Driver实现类,而DriverManager又必须使用这些Driver来建立连接。

为了解决这个矛盾,早期的DriverManager引入了线程上下文类加载器(Thread Context ClassLoader):它会获取当前线程的上下文类加载器(默认就是Application ClassLoader),然后用这个类加载器去加载应用类路径下的Driver实现。这就绕过了双亲委派的常规流程——父加载器主动让子加载器加载自己无法加载的类,这就是所谓的“破坏双亲委派模型”的核心原因。

2. 现在你看到的:为什么所有类都是Application ClassLoader加载?

随着JDBC 4.0及以后版本引入了SPI(Service Provider Interface)机制,现在的实现变得更简洁,但核心的类加载逻辑本质没变,只是你看到的表象不同:

  • 现在的数据库驱动(比如mysql-connector-java)会在META-INF/services/java.sql.Driver文件中声明自己的Driver实现类,DriverManager初始化时会通过ServiceLoader自动扫描并加载这些实现类。而ServiceLoader默认会使用线程上下文类加载器(也就是Application ClassLoader)来加载这些Driver类。
  • 当你调用DriverManager.getConnection()时,DriverManager会遍历已经注册的Driver实例,这些实例对应的Driver类都是被Application ClassLoader加载的,所以你在调试或查看类加载器时,会看到所有相关类都由Application ClassLoader加载。

3. 为什么“破坏双亲委派”的说法依然成立?

虽然你看到的类都是Application ClassLoader加载的,但底层的类加载逻辑依然打破了双亲委派的规则:

  • 由Bootstrap ClassLoader加载的DriverManager,本应只能使用Bootstrap加载的类,但它通过线程上下文类加载器,主动让Application ClassLoader加载它无法访问的Driver实现类,并使用这些类的实例。
  • 这违背了双亲委派模型“父加载器优先加载,子加载器仅加载父加载器无法加载的类”的核心原则,本质上是一种“反向委托”——父加载器委托子加载器加载类,这就是资料中说JDBC破坏双亲委派模型的原因。

举个对应你代码的例子,这段逻辑:

public static void doingJdbc(){ 
    try { 
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/design", "root", "fengcs"); 
        String sql = "select * from tb_user"; 
        PreparedStatement preparedStatement = connection.prepareStatement(sql); 
        preparedStatement.executeQuery(); 
        // ... 后续逻辑
    } catch (Exception e) {
        e.printStackTrace();
    }
}

在调用getConnection之前,DriverManager已经通过ServiceLoader和线程上下文类加载器,加载了Application ClassLoader范围内的MySQL Driver,所以整个调用链里的类都是Application加载的,但背后的加载机制依然是突破了双亲委派的限制。

内容的提问来源于stack exchange,提问作者lucare

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:24:14