Java 9中将普通JAR改造成显式自动模块的唯一标准方式是通过JVM启动参数(如--module-path或--add-modules)指定模块名,而非修改JAR本身;其中Automatic-Module-Name仅在可重打包时适用。

Java 9 引入了模块系统(JPMS),但大多数第三方 JAR 仍是“普通 JAR”(即未声明 module-info.class 的非模块化 JAR)。这类 JAR 在模块路径(--module-path)上运行时,会被视为 自动模块(Automatic Module)——JVM 会根据 JAR 文件名(去掉版本号和扩展名)自动生成一个模块名,并导出所有包、读取所有依赖。
但“自动模块”是过渡机制,不推荐长期依赖。若你想**主动将普通 JAR 改造成显式自动模块(即保留自动模块行为,但可控命名与依赖)**,实际有且仅有一种标准方式:不改 JAR 本身,而是通过 JVM 启动参数显式声明其模块名。下面分几种常见需求说明:
✅ 方式一:用 --add-modules + --module-path 触发自动模块(默认行为)
这是最常用、最轻量的做法,无需修改 JAR,只需规范使用模块路径:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 把普通 JAR(如
guava-31.1-jre.jar)放在--module-path(而非-cp)中; - JVM 自动将其识别为自动模块,模块名为
guava(去掉版本号-31.1-jre和后缀.jar); - 你的代码可通过
requires guava;声明依赖(需你自己的模块有module-info.java); - 注意:若 JAR 名含非法字符(如
.、-过多),JVM 会按规则规范化(例如log4j-api-2.20.0.jar→ 模块名log4j.api)。
✅ 方式二:用 --add-modules 显式指定自动模块名(覆盖默认推断)
当默认推断的模块名不理想(如含冲突、太长或含非法字符),可用 JVM 参数强制指定:
立即学习“Java免费学习笔记(深入)”;
- 重命名 JAR 文件为符合模块名规范的名称(如将
mylib-1.0.0.jar改为com.example.mylib.jar),再放至模块路径; - 或保持原名,启动时加参数:
--add-modules com.example.mylib; - 此时 JVM 会尝试将
com.example.mylib解析为模块——若该名在模块路径中无显式模块,就查找匹配的自动模块(如mylib-1.0.0.jar),并赋予它这个名称; -
⚠️ 注意:此方式要求模块路径中存在能被映射到该名的 JAR(JVM 会按文件名启发式匹配),否则报错
Module not found。
❌ 不可行的方式(常见误区)
-
反编译 + 手动添加
module-info.class:不可行。普通 JAR 缺少模块描述,强行注入module-info.class会导致签名失效(如有)、验证失败,且无法保证包导出/服务声明正确; -
用
jmod将 JAR 打包成.jmod:jmod 是 JDK 内部格式,不支持普通 JAR 转换,且.jmod不能直接运行(仅用于构建 JDK 或jlink); -
修改 MANIFEST.MF 添加
Automatic-Module-Name:这是唯一真正改造 JAR 本身的方法,但需你有 JAR 的发布权限或能重新打包——在META-INF/MANIFEST.MF中添加一行:Automatic-Module-Name: com.example.guava。
这样 JVM 会优先使用该名称,而非推断名。适用于你维护该库或可 fork 修改发布流程的场景。
? 实用建议
- 优先使用
--module-path启动,让 JVM 自动处理,省心且兼容性好; - 对关键依赖(如 Spring、Jackson),查其最新版是否已提供模块化支持(如
spring-core6+ 已含module-info.class); - 若需稳定模块名,联系库作者在
META-INF/MANIFEST.MF中添加Automatic-Module-Name; - 避免在生产模块系统中过度依赖自动模块——它们无法封装包、不能声明服务、且模块名易变。
本质上,“改造为自动模块”不是给 JAR 加模块,而是告诉 JVM 如何把它当作模块来用。核心动作只有两个:放进模块路径,或用启动参数引导命名。不复杂但容易忽略细节。

















