jdk9变化
关键变化点
步骤 |
传统双亲委派(JDK 8 及以前) |
JPMS 双亲委派(JDK 9+) |
可见性检查 |
无(仅依赖类路径) |
优先检查模块间的 、 、 |
委派规则 |
无条件委派给父类加载器 |
受模块可见性限制,即使父类能找到类也可能拒绝加载 |
加载范围 |
类路径( )和扩展目录 |
模块路径( )和自动模块 |
核心类隔离 |
依赖引导类加载器加载核心类 |
由模块系统强制隔离,防止非法访问核心模块 |
动态加载 |
依赖类路径和反射权限 |
需遵循模块的 和 规则 |
三、示例流程对比
场景 1:加载核心模块类(如java.lang.String)
plaintext
传统流程: 应用类加载器 → 扩展类加载器 → 引导类加载器(成功加载) JPMS流程: 1. 应用类加载器检查模块可见性:java.base模块对所有模块自动可见 2. 委派至引导类加载器(成功加载)
场景 2:跨模块加载非导出类
java
// 模块A module a { exports com.example.a.public; // 仅导出public包 // 未导出com.example.a.internal } // 模块B尝试加载com.example.a.internal.Class JPMS流程: 1. 应用类加载器检查模块可见性:模块B未被授权访问a.internal 2. 即使委派至父类加载器(能找到类),仍因可见性规则拒绝加载 3. 抛出ClassNotFoundException
场景 3:加载自动模块类
java
// 自动模块legacy.jar(未声明module-info.java) // 包含类com.legacy.LegacyClass // 模块modern尝试加载LegacyClass JPMS流程: 1. 应用类加载器检查模块可见性: - 自动模块向所有模块导出所有包 - 模块modern隐式requires所有自动模块 2. 委派至父类加载器(未找到) 3. 应用类加载器从模块路径加载LegacyClass(成功)
四、流程图(简化版)
流程图(简化版)
plaintext
类加载请求 → [当前加载器] | ├─ 检查已加载? → 是 → 返回类 | ├─ 检查模块可见性? → 否 → 抛出ClassNotFoundException | ├─ 委派给父类加载器 → [父类加载器重复上述流程] | └─ 父类加载失败 → 自身尝试加载 → 成功 → 返回类 → 失败 → 抛出ClassNotFoundException
五、总结
JDK 9 的双亲委派模型通过模块可见性优先和加载器与模块解耦,实现了更严格的类访问控制:
- 安全性增强:防止未授权模块访问其他模块的非导出类。
- 模块化支持:类加载与模块依赖关系紧密绑定,确保依赖一致性。
- 兼容性保留:通过自动模块机制支持传统 JAR 文件,平滑过渡到模块化系统。
类加载过程