关键在于将JAR放至模块路径(--module-path)并主动设Automatic-Module-Name,避免文件名推导冲突;需规避split-package、补全opens/uses声明,并验证jdeps输出。

把传统 JAR 包当作自动模块引入,关键不是“能不能用”,而是“用得稳”。它不改变 JAR 本身,但会改变 JVM 如何看待它——放在模块路径上,它就自动获得模块身份;放错位置或配置不当,反而埋下运行时隐患。
确认 JAR 已进入模块路径(不是类路径)
自动模块只在 --module-path(或 -p)下生效。如果仍用 -cp 或 --class-path 启动,JAR 还是归入未命名模块,享受不到模块边界保护,也触发不了自动模块机制。
- 正确写法:
java --module-path lib/:lib-legacy/ --module myapp/com.example.Main - 错误写法:
java -cp lib/guava.jar:lib/log4j-core.jar MyApp(此时 guava 和 log4j 都在未命名模块里,无隔离) - IDE 中需检查运行配置:确保 “Use classpath of module” 未勾选,且 “Module path” 栏位填入 JAR 所在目录
主动指定 Automatic-Module-Name(强烈推荐)
靠文件名推导模块名(如 fastjson-1.2.83.jar → fastjson.1.2.83)容易出问题:含数字、短横线、多版本并存时易冲突,还可能生成非法标识符(如以数字开头)。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- Maven 构建时注入(推荐):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>com.alibaba.fastjson</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin> - 已有 JAR 可用
jar -uf补充 MANIFEST:echo "Automatic-Module-Name: com.google.guava" >> MANIFEST.MF && jar -uf guava.jar META-INF/MANIFEST.MF
验证并规避 split-package 风险
两个不同 JAR 导出同名包(比如 commons-lang3-3.12.0.jar 和 commons-lang3-4.0.jar 都导出 org.apache.commons.lang3),JVM 启动直接失败。
立即学习“Java免费学习笔记(深入)”;
- 先查自动模块名:
jdeps --print-module-deps your-app.jar - 再查包级来源:
jdeps -s --module-path lib/ your-app.jar | grep "org.apache.commons" - 发现重复?必须移除一个 JAR,或改用
--patch-module org.apache.commons.lang3=commons-lang3-4.0.jar(仅限调试,不可用于生产) - 注意:自动模块默认导出所有包,所以只要存在同名包,就构成冲突,不看是否实际使用
补足反射与服务加载能力
自动模块不声明 opens 或 uses,因此即使类在 JAR 里,反射访问或 ServiceLoader 加载也会失败。
- 反射受限类(如
sun.misc.Unsafe):--add-opens java.base/sun.misc=ALL-UNNAMED - 调用第三方 SPI 接口(如
javax.xml.bind.JAXBContext):
在你自己的module-info.java中添加:uses javax.xml.bind.JAXBContext; - 读取
META-INF/services/xxx:确保该资源所在包已opens给调用方模块,或改用Thread.currentThread().getContextClassLoader().getResource()

















