V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
zxCoder
V2EX  ›  问与答

双亲委派模型

  •  
  •   zxCoder · 2020-04-09 19:52:47 +08:00 · 2311 次点击
    这是一个创建于 1683 天前的主题,其中的信息可能已经有所发展或是发生改变。

    为什么网上都说 JDBC 各个数据库的 Driver 的加载就是破坏了双亲委派模型。

    比如这一段

    “ JDBC 之所以要破坏双亲委派模式是因为,JDBC 的核心在 rt.jar 中由启动类加载器加载,而其实现则在各厂商实现的的 jar 包中,根据类加载机制,若 A 类调用 B 类,则 B 类由 A 类的加载器加载,也就是说启动类加载器要加载 jar 包下的类,我们都知道这是不可能的 “

    我不能理解根据类加载机制,若 A 类调用 B 类,则 B 类由 A 类的加载器加载,也就是说启动类加载器要加载 jar 包下的类,我们都知道这是不可能的这句话,前半句和后半句有什么联系吗,我知道启动类加载器不能加载 jar 包下的类,那我们为什么一定要用启动类加载器呢?

    11 条回复    2020-04-10 13:38:44 +08:00
    falsemask
        1
    falsemask  
       2020-04-09 20:24:13 +08:00
    JDBC 在 rt.jar 包下,只能由 Bootstrap ClassLoader 加载,但是具体的实现类在 xxx.jar 中,这个 jar 没法用 Bootstrap ClassLoader 加载,需要用 Thread Context ClassLoader
    zxCoder
        2
    zxCoder  
    OP
       2020-04-09 21:11:13 +08:00
    @falsemask 那就用 Application ClassLoader 不行吗
    falsemask
        3
    falsemask  
       2020-04-09 21:29:54 +08:00
    @zxCoder JDBC 用的就是 Application ClassLoader,我没描述清楚,Thread Context ClassLoader 不是一个具体的类,是 Thread 的一个变量 private ClassLoader contextClassLoader,默认就是 Application ClassLoader,可以看下这个方法:java.sql.DriverManager#getConnection(java.lang.String, java.util.Properties, java.lang.Class<?>)
    zerozerone
        4
    zerozerone  
       2020-04-09 21:39:40 +08:00 via Android
    看不懂你在说啥
    zerozerone
        5
    zerozerone  
       2020-04-09 21:41:48 +08:00 via Android
    根据双亲委派,application class loader 先委托给自己的父加载器去加载 JDBC 实现,但是实现是在第三方 jar 包里的,必然加载不到,因此这里要绕过双亲委派,直接使用 application class loader 去加载实现类,就是在这里打破的双亲委派机制
    zerozerone
        6
    zerozerone  
       2020-04-09 21:47:12 +08:00 via Android   ❤️ 2
    @zerozerone 我这里说错了 DriverManager 默认用自己的类加载器加载 JDBC,它自己的加载器是 bootstrap class loader,必然加载不到实现类,就抛异常了,因此需要从 thread context 里拿到 application class loader,用 application class loader 去直接加载实现类
    GM
        7
    GM  
       2020-04-09 21:54:38 +08:00
    “双亲委派”这个翻译极具误导性,实际上如果翻译好的话,要容易理解很多。
    mazai
        8
    mazai  
       2020-04-09 23:43:30 +08:00   ❤️ 1
    因为 Driver 这个接口就是被启动类加载器所加载的,要使用具体实现则需要厂商的 jar 包,但是启动类加载器是无法加载 classpath 下的 jar 包,所以就引入了一个上下文类加载器( context classloader )来加载,默认情况下上下文类加载器就是我们的应用类加载器( app classloader ),应用类加载器显然是可以加载 classpath 下的 jar 包的。即打破了双亲委派的机制。
    zxCoder
        9
    zxCoder  
    OP
       2020-04-10 08:54:07 +08:00
    @falsemask 我理解是比如 JDBC
    原来是需要 Class.forName(); DriverManager.getConnection(); 这里没有嵌套关系,所以一个用 Application 加载器,一共用 bootstrap 加载器。

    然后 JDBC4.0 后,可以直接 DriverManager.getConnection(); 里面就自动调用了 Class.forName(); 有嵌套的关系,所以里面的 Class.forName 就得用外面的 Bootstrap 加载器来加载,所以才不行得用线程上下文加载器。
    falsemask
        10
    falsemask  
       2020-04-10 09:41:19 +08:00
    @zxCoder 我和你理解的一样,引入了 SPI 机制之后不需要手写 Class.forName(),需要用 context Classloader 来加载三方 jar 的类
    zxCoder
        11
    zxCoder  
    OP
       2020-04-10 13:38:44 +08:00
    @falsemask 谢谢 比较清楚了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6231 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:32 · PVG 10:32 · LAX 18:32 · JFK 21:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.