自动模块机制使非模块化jar在模块路径上获得模块身份:按manifest中automatic-module-name指定或文件名推导命名,默认导出所有包,但需确保路径正确、声明对齐、权限手动授权。

Java 模块系统(JPMS)对非模块化 JAR 包的处理,核心不是“绕过规则”,而是利用自动模块机制补全缺失的模块语义。只要路径、声明、访问权限三者对齐,老 JAR 就能稳稳跑在模块路径上。
让非模块化 JAR 成为自动模块
不含 module-info.class 的 JAR(如 fastjson-1.2.83.jar、commons-lang3-3.12.0.jar)被放进模块路径(--module-path)后,JVM 会自动赋予它一个模块身份:
- 若 JAR 的
META-INF/MANIFEST.MF中声明了Automatic-Module-Name: com.alibaba.fastjson,就直接用该名 - 否则按文件名推导:去掉版本号和
.jar,小写,短横线/下划线转点号 →fastjson-1.2.83.jar→fastjson;log4j-core-2.20.0.jar→log4j.core
推导名可直接写进 module-info.java:
module com.example.app {
requires fastjson;
requires log4j.core;
exports com.example.api;
}
必须走模块路径,不能混用类路径
“变量读不到”“Class.forName 找不到类”“Properties.load 失败”——90% 是因为 JAR 被错放在 -cp(类路径)而非 --module-path(模块路径)。只有在模块路径上,JVM 才会触发自动模块机制并建立可读性契约。
- 编译时:用
javac --module-path mods -d out src/module-info.java src/MyClass.java - 运行时:用
java --module-path out:mods --module com.example.app/com.example.MyClass - Maven 用户:确保
maven-compiler-plugin和maven-surefire-plugin都启用<usemodulepath>true</usemodulepath>
反射、SPI、资源访问要手动授权
自动模块默认不开放反射、不声明服务、不导出包给其他模块——这会导致 InaccessibleObjectException 或 ServiceConfigurationError。
- 需读取第三方库的
public static final String VERSION?在module-info.java中加opens声明对应包,或启动时加--add-opens xxx/yyy=ALL-UNNAMED - 用
ServiceLoader.load(MyService.class)加载实现类?在module-info.java中写uses MyService; - 要加载
META-INF/services/或配置文件?确保调用方模块已opens对应包,或改用MyClass.class.getModule().getResourceAsStream("xxx.conf")
长期建议:主动补全 module-info
依赖自动推导名存在风险(如含数字、多版本冲突、命名模糊)。更可控的做法是为关键依赖生成专属 module-info.java:
- 执行:
jdeps --ignore-missing-deps --generate-module-info . hutool-core-5.8.29.jar,生成hutool.core/module-info.java - 编译:
javac -d . hutool.core/module-info.java - 注入:
jar -u -f hutool-core-5.8.29.jar -C hutool.core module-info.class - 再配合 Maven 的
<automatic-module-name></automatic-module-name>MANIFEST 属性,在构建阶段统一治理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











