自动模块是java 9+中将无module-info.java的jar置于模块路径时,jvm自动推导模块名并隐式导出所有包、依赖java.base的过渡机制,适用于传统项目渐进式模块化。

Java 9+ 的模块系统(JPMS)并不强制要求项目立刻重构成显式模块,尤其对传统项目而言,直接写 module-info.java 可能带来兼容性风险或重构成本。但你可以“渐进式”启用自动模块(Automatic Module)特性,在不改动源码结构的前提下,获得模块路径管理、强封装提示、依赖可见性控制等实际好处。
什么是自动模块?为什么适合传统项目?
当你把一个普通 JAR(无 module-info.class)放到模块路径(--module-path)而非类路径(-cp)启动时,JVM 会自动为其推导出一个模块名,并将其视为“自动模块”。它的核心特点是:
- 模块名默认来自 JAR 文件名(如
guava-32.1.3-jre.jar→ 模块名guava) - 自动导出所有包(即其他模块可直接访问其 public 类)
- 隐式依赖
java.base,并可被显式requires引用 - 与显式模块共存,可作为过渡桥梁
在构建工具中启用模块路径(关键一步)
传统项目通常只用类路径,要让自动模块生效,必须改用模块路径启动——这需要构建工具配合:
-
Maven:在
pom.xml中启用release并配置运行参数
<properties><maven.compiler.release>17</maven.compiler.release></properties><plugin><groupid>org.apache.maven.plugins</groupid><artifactid>maven-surefire-plugin</artifactid><configuration><argline>--module-path ${project.build.outputDirectory} --add-modules ALL-SYSTEM</argline></configuration></plugin>
-
Gradle:在
build.gradle中启用模块推断,并确保 JAR 输出为模块路径友好的形式
java {
modularity.inferModulePath = true
}
run {
jvmArgs = ['--module-path', 'build/classes/java/main', '--add-modules', 'ALL-SYSTEM']
}
这样,即使没有 module-info.java,你的项目也能跑在模块路径上,所依赖的第三方 JAR(如 Jackson、Log4j)就自然成为自动模块。
给关键依赖加 Automatic-Module-Name(提升稳定性)
自动模块名由文件名推导,容易因版本号变化而失效(如 mylib-1.0.jar vs mylib-1.1.jar)。你可以在自己维护的 JAR 的 META-INF/MANIFEST.MF 中声明稳定名称:
Automatic-Module-Name: com.example.mylib
这样无论 JAR 文件名怎么变,模块名始终是 com.example.mylib,方便后续在 module-info.java 中写 requires com.example.mylib;,为将来显式模块化铺路。
逐步向显式模块演进(可选但推荐)
当项目稳定运行在模块路径后,可小步引入显式模块:
- 在主模块添加最简
module-info.java:module myapp { requires java.desktop; } - 用
jdeps --module-path lib/ --multi-release 17 .分析依赖图,识别哪些 JAR 已支持模块化 - 优先将内部通用工具模块(如
utils)转为显式模块,再让业务模块requires它
这个过程不破坏原有逻辑,却能让编译期检查依赖完整性,避免运行时 NoClassDefFoundError。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











