如何通过 ClassLoader 的 loadClass 递归逻辑理解双亲委派模型在防止核心库篡改时的作用

小婷酱_9840

小婷酱_9840

2026-04-29

929人浏览

原创

loadClass 方法强制执行“先委托父加载器,失败再自行查找”的双亲委派逻辑;自定义 java.lang.String 无效,因 BootstrapClassLoader 优先加载 rt.jar 中的版本并阻止后续加载;破坏该机制会导致 LinkageError、类隔离失效及安全沙箱崩溃。

如何通过 classloader 的 loadclass 递归逻辑理解双亲委派模型在防止核心库篡改时的作用

loadClass 方法里藏着的“先问爹,再问爷”逻辑

loadClass 是 ClassLoader 的核心入口方法,它的默认实现(在 java.lang.ClassLoader 中)写死了双亲委派流程:收到类加载请求后,不立即查找本地资源,而是先调用 parent.loadClass();父加载器返回 null 或抛出 ClassNotFoundException,才轮到自己调用 findClass() 去查。这个“向上委托 + 向下 fallback”的硬编码逻辑,就是双亲委派模型的全部骨架。

它不是靠继承关系或接口约束实现的,而是靠每个子类加载器在构造时显式持有父加载器引用,并在 loadClass 里强制调用它——哪怕你自定义一个 MyClassLoader 继承 ClassLoader,只要没重写 loadClass,就自动遵守这套规则。

为什么自定义 java.lang.String 不会生效

当你写一个 public class String extends Object { ... } 并试图用 MyClassLoader 加载它时,loadClass("java.lang.String") 会一路委托到 BootstrapClassLoader;后者只认 $JAVA_HOME/jre/lib/rt.jar 里的 java/lang/String.class,并成功返回对应 Class 对象;后续所有加载器都不会再尝试加载——你的类根本不会被 findClass 触达。

常见错误现象包括:

  • 运行时报 NoClassDefFoundError: java/lang/String(其实是启动失败,因 JVM 检测到类型不一致)
  • 编译通过但运行时提示 “找不到 main 方法”,因为 JVM 找到的是 rt.jar 中的 String,而它没有 main 入口
  • 直接抛 SecurityException:JVM 在初始化阶段会对 java.* 包名做白名单校验,连加载机会都不给

破坏双亲委派的典型场景与风险

有些框架(如 Tomcat、OSGi)会主动绕过默认 loadClass 流程,改为“先自己查,查不到再委托”。这种破坏不是 bug,而是为了解决实际问题,比如 Web 应用间类隔离、热部署等。

SSL Certificate Monitor
SSL Certificate Monitor

检查一个或多个域名的 SSL/TLS 证书到期时间、颁发者、协议及 SAN 信息,用于应要求检查证书、监控到期或验证 HTTPS 等场景。

下载

但随意破坏会触发严重后果:

  • 若应用类加载器优先加载了 java.util.ArrayList 的篡改版本,可能导致 BootstrapClassLoader 加载的 java.lang.ClassLoader 在运行时调用它,引发 LinkageError(类链接冲突)
  • 不同加载器加载的同名类,即使字节码完全一样,在 JVM 中也被视为不同类,无法强转、无法共用静态变量
  • System.setProperty("java.security.manager", "xxx") 等安全机制依赖双亲委派保证核心类可信,破坏后沙箱形同虚设

验证双亲委派是否生效的简单方式

不必翻源码或调试 JVM,只需观察类的 ClassLoader 引用链:

System.out.println(String.class.getClassLoader()); // null(Bootstrap 不是 Java 对象)
System.out.println(MyAppClass.class.getClassLoader()); // AppClassLoader 实例
System.out.println(MyAppClass.class.getClassLoader().getParent()); // ExtClassLoader 实例
System.out.println(MyAppClass.class.getClassLoader().getParent().getParent()); // null(Ext 的 parent 是 Bootstrap)

关键点在于:java.lang.* 下所有类的 getClassLoader() 都返回 null,这是 JVM 硬编码的标识;而任何用户类,只要没被自定义加载器劫持,其加载器链最终都会指向 null —— 这条链本身,就是双亲委派在内存中的投影。

真正容易被忽略的,是那个看似无害的 findClass:它只负责“找字节码”,不负责“解析父子关系”;一旦你重写了 loadClass 却忘了调用父类逻辑,或者把 parent 设为 null,整个安全边界就从根上断了。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

ssl

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

11577

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

8682

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

7472

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1224

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

988

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1476

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

3049

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20291

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1335

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 0.1万人学习