java模块化系统(jpms)通过模块路径、module-info.java声明、类加载器分层及双亲委派受控调整四者协同,将依赖控制前移至编译与启动阶段,并由类加载器强制执行封装与访问规则。

Java 模块化系统(JPMS)不是简单地“管理类加载依赖”,而是通过模块声明与类加载机制深度协同,把依赖控制从运行时提前到编译和启动阶段,并由类加载器在加载过程中强制执行。核心在于:模块路径、模块声明、类加载器分层与双亲委派的受控调整四者共同作用。
模块路径取代类路径,决定类加载器“找什么”
传统 classpath 被 --module-path 取代。JVM 仅对模块路径上的 JAR 做模块化处理:
- 含 module-info.class 的 JAR → 视为命名模块,由平台或系统类加载器按模块图加载
- 不含 module-info.class 但放在模块路径上 → 自动模块(Automatic Module),名称由 JAR 文件名推导(如 guava-32.1.3-jre.jar → com.google.common),全部包默认导出
- 放在 classpath 上的 JAR → 归入未命名模块(Unnamed Module),可访问所有导出包,但不能被命名模块直接 requires
module-info.java 是类加载的“准入规则说明书”
每个命名模块的 module-info.java 不只是编译配置,它直接影响类加载器能否成功加载类:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- requires:声明依赖模块。若所需模块不在模块图中(如缺失或未导出对应包),JVM 启动失败,不等到运行时才报 NoClassDefFoundError
- exports:指定哪些包对外可见。类加载器检查调用方是否有权限访问该包,否则抛 IllegalAccessError
- opens:允许反射访问(如框架需注入私有字段),类加载器据此放宽封装限制
- uses / provides:配合 ServiceLoader,类加载器根据模块图定位服务实现,而非全路径扫描
类加载器层级重构,让模块边界真正落地
Java 9+ 将类加载器扩展为四层,每层承担明确的模块职责:
- 启动类加载器:加载 JVM 核心类(如 java.lang.*),不参与模块解析
- 平台类加载器:专管 JDK 平台模块(java.base、java.sql 等),不继承自 ClassLoader,但参与双亲委派——例如加载 java.time.LocalDate 时,系统类加载器会委托它,它再依据 java.base 的 exports 判断是否放行
- 系统类加载器:加载应用模块和自动模块,依据模块图解析依赖链
- 自定义类加载器:可创建模块上下文(ModuleLayer),支持动态模块加载
双亲委派不是铁律,模块策略可显式绕过
模块化并未废弃双亲委派,而是引入“受控例外”:
- 框架(如 Spring、Hibernate)需要反射访问用户模块内部类时,可通过 JVM 参数 --add-opens 强制打开包:
--add-opens my.app/com.example.internal=ALL-UNNAMED - 这种“开包”行为由平台/系统类加载器在初始化阶段注册,属于模块策略的一部分,而非破坏委派模型
- 普通场景仍严格遵循委派:先查父加载器是否已加载且可访问,再尝试自身加载
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










