如何打破双亲委派机制?
未标记
考查重点:委派顺序与自定义加载。自定义 loadClass 对指定业务包改为先自找后委派;只重写 findClass 通常仍保留父优先逻辑
本题目录
参考答案
本答案基于相关资料,由 AI 辅助编写,供学习与面试准备参考。如有疏漏,欢迎反馈指正。
核心回答
默认ClassLoader通常先检查是否已经加载,再委托父加载器,父级找不到时才调用自己的findClass。改变这种顺序,可以自定义loadClass,对特定业务包采用“先自己找、再向父级委托”的策略;只重写findClass来改变字节码来源,通常仍保留双亲委派。
另外,线程上下文类加载器可让框架显式使用调用方提供的加载器寻找实现,这常用于SPI。它是选择另一条加载入口,不等于所有类都改成子优先。
为什么需要改变规则
插件容器或Web应用可能依赖同名但不同版本的类,需要不同加载器隔离。可让公共接口与平台类由共同父加载器提供,插件自己的实现和依赖由插件加载器处理;不能对所有包无差别子优先。
实现时仍需处理已加载检查、并发加载同步和失败回退,避免重复定义同名类。卸载插件还要释放线程、缓存和其他强引用,否则丢掉加载器变量不代表其类能立刻被卸载。
核心类同名能否替换
自定义java.lang.String不会因为改变委派顺序就替换系统String。默认情况下先返回平台已定义的核心类;普通自定义加载器尝试自行定义java.包类时,还会受到defineClass等机制的限制。双亲委派是保护的一部分,不能把核心类完整性完全归因于一段父优先代码。
追问
两个加载器加载相同二进制名称,可能得到不同类型。插件对象要转换为公共接口时,双方应共享同一个接口类型的定义;否则即使类名相同,也可能发生ClassCastException或链接约束问题。
参考资料
- 国内:JavaGuide / Snailclimb:类加载器详解:借鉴默认委派与自定义规则的对比,解释正文中重写 findClass 与改变 loadClass 查找顺序的区别。
- 国内:JavaGuide / Snailclimb:类加载过程详解:加载和验证的分工说明改变字节来源不代表改变委派规则,也不代表绕过类型约束。
- 国内:说出你的愿望吧丷 / JavaGuide收录:大白话带你认识JVM:参考 Java 文件运行流程与类加载器的职责,交代正文中加载字节码与加载器委派的关系。
- 国外:Oracle:ClassLoader — Java SE21:默认查找顺序和java包定义限制说明自定义加载器为什么不能任意替换核心类。
- 国外:Oracle:JVM Specification SE21 — Creation and Loading:二进制名称与定义加载器共同标识类型的规则说明隔离加载后为何可能出现类型转换问题。
