1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00

Update classloader.md

This commit is contained in:
Guide 2025-01-02 16:39:49 +08:00
parent 8a47f66748
commit 7e3887acb4

View File

@ -283,13 +283,13 @@ protected Class<?> loadClass(String name, boolean resolve)
双亲委派模型是 Java 类加载机制的重要组成部分,它通过委派父加载器优先加载类的方式,实现了两个关键的安全目标:避免类的重复加载和防止核心 API 被篡改。 双亲委派模型是 Java 类加载机制的重要组成部分,它通过委派父加载器优先加载类的方式,实现了两个关键的安全目标:避免类的重复加载和防止核心 API 被篡改。
JVM 区分不同类的方式不仅仅基于类名,相同的类文件被不同类加载器加载会生成不同的类。双亲委派模型确保核心类总是由 `BootstrapClassLoader` 加载,保证了核心类的唯一性。 JVM 区分不同类的依据是类名加上加载该类的类加载器,即使类名相同,如果由不同的类加载器加载,也会被视为不同的类。 双亲委派模型确保核心类总是由 `BootstrapClassLoader` 加载,保证了核心类的唯一性。
例如,当应用程序尝试加载 `java.lang.Object` 时,`AppClassLoader` 会首先将请求委派给 `ExtClassLoader``ExtClassLoader` 再委派给 `BootstrapClassLoader``BootstrapClassLoader` 会在 JRE 核心类库中找到并加载 `java.lang.Object`,从而保证应用程序使用的是 JRE 提供的标准版本。 例如,当应用程序尝试加载 `java.lang.Object` 时,`AppClassLoader` 会首先将请求委派给 `ExtClassLoader``ExtClassLoader` 再委派给 `BootstrapClassLoader``BootstrapClassLoader` 会在 JRE 核心类库中找到并加载 `java.lang.Object`,从而保证应用程序使用的是 JRE 提供的标准版本。
有很多小伙伴就要说了:“那我绕过双亲委派模型不就可以了么?”。 有很多小伙伴就要说了:“那我绕过双亲委派模型不就可以了么?”。
然而即使攻击者绕过了双亲委派模型Java 仍然具备更底层的安全机制来保护核心类库。`ClassLoader``preDefineClass` 方法会在定义类之前进行类名校验。任何以 `"java."` 开头的类名都会触发 `SecurityException`,阻止恶意代码定义或加载伪造的核心类。 同时,`defineClass` 方法被声明为 `final`,防止子类覆盖该方法并绕过安全检查。 然而即使攻击者绕过了双亲委派模型Java 仍然具备更底层的安全机制来保护核心类库。`ClassLoader``preDefineClass` 方法会在定义类之前进行类名校验。任何以 `"java."` 开头的类名都会触发 `SecurityException`,阻止恶意代码定义或加载伪造的核心类。
JDK 8 中`ClassLoader#preDefineClass` 方法源码如下: JDK 8 中`ClassLoader#preDefineClass` 方法源码如下:
@ -326,8 +326,6 @@ private ProtectionDomain preDefineClass(String name,
JDK 9 中这部分逻辑有所改变,多了平台类加载器(`getPlatformClassLoader()` 方法获取),增强了 `preDefineClass` 方法的安全性。这里就不贴源码了,感兴趣的话,可以自己去看看。 JDK 9 中这部分逻辑有所改变,多了平台类加载器(`getPlatformClassLoader()` 方法获取),增强了 `preDefineClass` 方法的安全性。这里就不贴源码了,感兴趣的话,可以自己去看看。
因此Java 的核心类库安全并非完全依赖于双亲委派模型,更重要的是对 `java.*` 开头类名的显式限制以及 `defineClass` 方法的 `final` 修饰符。这些底层机制构筑了更加牢固的安全防线,有效地阻止了恶意代码对核心类的篡改,即使双亲委派机制失效也能提供保护。 双亲委派模型主要负责优先加载父加载器路径下的类,避免重复加载,而类名校验和 `final` 修饰符则提供了更底层的安全保障,阻止恶意替换核心类。
### 打破双亲委派模型方法 ### 打破双亲委派模型方法
~~为了避免双亲委托机制,我们可以自己定义一个类加载器,然后重写 `loadClass()` 即可。~~ ~~为了避免双亲委托机制,我们可以自己定义一个类加载器,然后重写 `loadClass()` 即可。~~