Java模块化系统(JPMS)通过module-info.java声明式封装、requires最小化依赖、ModuleLayer运行时隔离及ServiceLoader服务机制,实现编译期检查、加载期失败、运行时不可达的强隔离。

Java 模块化系统(JPMS)实现模块间高效隔离,核心不在“打包”或“分目录”,而在于语言级的访问控制 + 运行时类唯一性保障 + 显式依赖契约。它不是靠人工管理路径或加锁,而是让非法访问在编译期报错、加载期失败、运行时根本不可达。
用 module-info.java 精确划定可见边界
模块隔离的第一道防线是声明式封装:
-
只 exports 实际需要暴露的包,比如
exports com.example.api;,绝不导出com.example.internal或整个模块名 - 未出现在 exports 中的包,连 public 类也无法被其他模块解析到——反射、Class.forName、甚至字节码工具都拿不到类符号
- 避免使用
open module,除非真需反射(如测试框架),否则会主动放弃封装保护
靠 requires 最小化依赖传递链
模块间的“可读性”由 requires 显式授予,不是默认开放:
- 不写 transitive,就只自己能读,下游模块看不到该依赖,防止意外暴露内部依赖(如把 jdk.unsupported 暴露给业务模块)
- 若只需调用 SPI 接口,用
uses com.example.spi.Service替代requires实现模块,解耦更干净 - 启动时若混用
--class-path,模块会被降级为“自动模块”,exports失效——必须统一用--module-path启动
利用 ModuleLayer 实现运行时多实例隔离
当需要多个逻辑上相同但状态独立的模块(如多租户、插件多版本),ModuleLayer 提供轻量级物理隔离:
立即学习“Java免费学习笔记(深入)”;
- 每个
ModuleLayer拥有独立的模块图,同名类(如ConfigService)在不同层中属于不同模块,静态变量互不干扰 - 无需自定义 ClassLoader,也不破坏双亲委派,JVM 自动保证类的唯一性 = 全限定名 + 模块名 + 所属 Layer
- 模块卸载时,对应 Layer 可整体释放,缓存、监听器、线程池等资源一并清理,无残留
配合服务机制替代对象直传
跨模块共享状态,不靠传实例,而靠接口抽象与服务发现:
- 定义纯接口(如
TokenGenerator),在提供方模块中provides TokenGenerator with JwtTokenGenerator; - 调用方声明
uses TokenGenerator;,通过ServiceLoader.load(TokenGenerator.class)获取实例 - 敏感字段(如密钥、上下文)始终留在提供方模块内,调用方只拿到能力,不接触原始数据


















