Java--JVM历史上有三次破坏双亲委派模型,是哪三次?

本文详细介绍了Java的类加载过程,包括加载、链接、初始化。重点讨论了双亲委派模型,解释了其作用和为什么需要这一模型。接着,文章揭示了双亲委派模型在JDK1.2之前、JNDI/JDBC、OSGI热部署以及JDK9模块系统中的四次破坏,分析了每次破坏的原因和解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个面试题来自一位群友的面试题分享

今天我们就来盘一盘这个面试题,不过在说双亲委派模型之前,我们得先简单了解下类加载。

类加载

我们平常写的代码是保存在一个 .java文件里面,经过编译会生成.class文件,这个文件存储的就是字节码,如果要用上我们的代码,那就必须把它加载到 JVM 中。


当然,加载到 JVM 生成 class 对象的来源不一定得是.class文件,也可以来自网络等等,反正只要是符合 JVM 规范的都行。

而类加载的步骤主要分为:加载、链接、初始化。

加载

其实就是找到字节流,然后将其加载到 JVM 中,生成类对象。这个阶段就是类加载器派上用场的阶段,等下我们再细说。

链接

这个阶段是要让生成的类对象融入到 JVM 中,分别要经历以下三个步骤:

验证就是检验一下加载的类是否满足 JVM 的约束条件,也就是判断是否合规。

准备就是为加载类的静态变量申请内存空间,并赋予初始值,例如是 int 类型那初始值就是 0。

解析就是将符号引用解析成为实际引用,讲人话就是:例如 Yes 类里面引用了一个 XX 类,那一开始 Yes 类肯定不知道 XX 类在内存里面的地址,所以就先搞个符号引用替代一下,假装知道,等类加载解析的时候再找到 XX 类真正地址,做一个实际引用。

这就是解析

### 三级标题:Java破坏双亲委派模型的原因 在 Java 的类加载机制中,双亲委派模型(Parent Delegation Model)是 JVM 的核心设计之一。该模型确保了类的唯一性和安全性,避免了类的重复加载,并且保证了像 `java.lang.Object` 这样的基础类在不同的类加载器环境中保持一致[^4]。 然而,在某些特定场景下,这种模型也存在局限性,需要被“破坏”,以实现更灵活的类加载行为。以下是破坏双亲委派模型的主要原因: #### 1. **顶层 ClassLoader 无法访问底层 ClassLoader 加载的类** 由于双亲委派模型的结构限制,顶层的类加载器(如启动类加载器)不能访问底层类加载器(如应用程序类加载器或自定义类加载器)所加载的类。这种单向委托关系导致了一些实际问题,例如 JDBC 驱动的加载过程[^1]。 JDBC 是一个典型的例子。JDBC 的接口定义在 JDK 提供的 `rt.jar` 中,由启动类加载器加载,而具体的数据库驱动(如 MySQL 的 `Driver` 类)通常是由应用程序类加载器加载的。当 JDBC 接口试图通过 `ServiceLoader` 或其他方式加载具体实现时,启动类加载器无法访问这些由子类加载器加载的类,这就需要绕过双亲委派模型来完成类加载任务。 #### 2. **引入扩展类加载器的历史事件** 在 Java 的发展过程中,曾经有一次对双亲委派模型破坏,即引入了扩展类加载器(Extension ClassLoader)。扩展类加载器位于引导类加载器和应用程序类加载器之间,它能够加载一些扩展库中的类,甚至可以访问引导类加载器所加载的类。这一设计打破了原有的严格父子委托关系,从而实现了更灵活的类加载策略[^3]。 虽然这种做法带来了灵活性,但也可能导致类加载的安全性和一致性问题。因此,为了恢复双亲委派模型的稳定性,Java 引入了系统类加载器(System ClassLoader),并在大多数情况下重新遵循了双亲委派机制。 #### 3. **打破双亲委派的典型手段** 可以通过重写 `ClassLoader` 的 `loadClass()` 方法来绕过默认的双亲委派逻辑。例如,某些框架(如 OSGi)利用这种方式实现了模块化、热部署等功能。这类场景要求类加载器优先加载自身路径下的类,而不是首先委托给父类加载器,从而实现类的隔离与动态更新[^2]。 ```java public class CustomClassLoader extends ClassLoader { @Override public Class<?> loadClass(String name) throws ClassNotFoundException { // 自定义类加载逻辑,跳过双亲委派 if (shouldLoadHere(name)) { return findClass(name); } return super.loadClass(name); } private boolean shouldLoadHere(String name) { // 判断是否由当前类加载器优先加载 return name.startsWith("com.example"); } } ``` #### 4. **安全性和性能的权衡** 尽管双亲委派模型有助于防止恶意代码注入并确保类的一致性,但在某些高级应用场景中,比如插件系统、容器服务、热部署等,必须牺牲部分安全性以换取更高的灵活性。此时,开发者可以选择适当地破坏双亲委派模型,但需谨慎处理类冲突和版本一致性问题。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值