不能通过module-info.java实现变量强隔离;它仅声明模块名、导出包、依赖关系、反射开放及服务契约,不控制类加载或静态变量作用域,变量隔离必须依赖独立ClassLoader实现类型物理隔离。

不能通过 module-info.java 实现变量强隔离。
module-info 的作用边界很明确
module-info.java 是 Java 9 引入的模块系统(JPMS)声明文件,它只负责:
- 声明模块名、导出(
exports)哪些包给其他模块使用 - 要求(
requires)哪些模块、是否可选或静态依赖 - 打开(
opens)包用于反射、服务加载等特殊场景 - 声明服务提供(
provides)与使用(uses)
它不控制类加载行为,也不影响类的实例化、静态字段生命周期或内存布局。即使两个模块都导出同名类 com.example.Config,只要它们被同一个 ClassLoader 加载(比如默认的 AppClassLoader),JVM 就只认作一个类——其 static int version = 1 在整个 JVM 中仍是共享的。
变量隔离的本质是类加载隔离
真正让变量(尤其是静态变量)互不干扰的关键,在于让同名类由不同的 ClassLoader 实例加载。此时:
- JVM 将它们视为完全无关的类型,哪怕字节码一模一样
- 各自拥有独立的方法区(Metaspace)数据,包括静态字段存储空间
- 模块 A 中的
Config.counter++不会影响模块 B 中的Config.counter
这和 module-info 是否存在、是否 exports 该类毫无关系。JPMS 模块系统本身仍运行在传统双亲委派模型之上,无法打破类加载器层级带来的类型唯一性约束。
可行的强隔离路径:绕过 JPMS,用 ClassLoader 分层
若你确实需要模块间变量强隔离(如插件系统、多租户配置类、动态脚本上下文),应放弃依赖 module-info,转而构建显式的类加载隔离层:
- 为每个业务模块创建独立的
URLClassLoader,且设置parent = null或自定义父加载器,彻底切断双亲委派 - 确保各模块 JAR 的 classpath 严格分离,避免交叉可见
- 通过接口契约通信(如定义在公共父类加载器中的 SPI 接口),禁止直接传递模块私有类的实例
- 配合资源隔离(如独立配置目录、线程上下文绑定)进一步强化边界
Spring 的 ServiceClassLoader、脚本引擎的 GroovyClassLoader、OSGi 的 Bundle ClassLoader,都是这一思路的成熟实践。
JPMS 与 ClassLoader 隔离不是替代关系,而是不同层级
JPMS 解决的是编译期与链接期的可见性、封装性与依赖声明问题;ClassLoader 隔离解决的是运行时类型的物理分隔与状态独立问题。二者可共存——例如用 JPMS 管理模块依赖拓扑,再用自定义 ClassLoader 加载每个模块的实现类。但切记:module-info 本身不提供变量隔离能力,也不能替代类加载器的职责。

















