⭐ 推荐:社区规则条款 V1.0

Java 模块化系统 JPMS 怎么用?

域名注册
域名注册 版主萌新站长 👑黑卡会员
发布于 2026-10-15 20:49 ·3 浏览 ·2 回复
内容摘要

JPMS 用法为在源码根目录写唯一的 module-info.java,用 requires/exports/opens/uses/provides 声明依赖与可见性,编译运行改用 module-path;它不同于 Maven 多模块,只有

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2131.html
转载请注明出处,版权归原作者所有。
他们都看过 1 人浏览过
juming
5.0/ 51 人评分
5 星100%
4 星0%
3 星0%
2 星0%
1 星0%

全部回复 2

juming
juming 初级会员萌新站长 1楼 2026-10-15 21:13

结论:JPMS 的落地顺序应该是「先拿一个模块写 module-info.java 跑通编译和运行,再考虑拆第二个」,一上手就全工程模块化,基本都会卡在反射和分包上。

补几个帖子里没展开的实操点。一是 module-info.java 的位置,Maven 工程必须放在 src/main/java 根目录(默认包)下,放到 src/main/java/com/example 里 javac 会直接报找不到模块声明;同时 maven-compiler-plugin 版本要够新,否则编译时不会走模块路径。二是 exports 和 opens 别混:exports 只管编译期可见性和 API 导出,反射访问还要靠 opens。Spring、Hibernate、Jackson 这类框架重度依赖反射,只写 exports 运行时就会抛 InaccessibleObjectException,临时可以用 --add-opens 救急,正式方案还是 opens xxx to 指定模块。

迁移路径上,第三方库没模块化时会被当成 automatic module,名字由 jar 名推导、并不稳定,可以先用 jdeps 分析依赖再动;应用层完全可以先不迁移,留在 unnamed module,它默认能读所有具名模块,兼容性没问题。

最常见的坑是分包(split package):同一个包名出现在两个模块里,JPMS 会直接拒绝加载,老项目里非常普遍,拆模块前先 grep 一遍包名冲突,否则会在启动那一刻才炸出来。

萝卜特棒
萝卜特棒 正式会员萌新站长 #1949 2楼 2026-10-15 21:19
juming:结论:JPMS 的落地顺序应该是「先拿一个模块写 `module-info.java` 跑通编译和运行,再考虑拆第二个」,一上手就全工程模块化,基本都会卡在反射…

认同,尤其 split package 那条,拆模块前先 grep 一遍包名,成本远低于改成运行时才发现。补几个同样高频但帖子里没展开的点。

automatic module 名字不稳定其实有正经解法:给没模块化的第三方 jar 在 MANIFEST.MF 里加一行 Automatic-Module-Name: xxx,名字就固定了,拿不到源码也可以用 maven-jar-plugin 或 shade 重打一遍。迁移前用 jar --describe-module --file a.jar 逐个确认实际推导出来的名字,比运行时抛 NoClassDefFoundError 再回头找划算得多。

另一个容易忽略的规则是:具名模块不能 requires 未命名模块。也就是说不能出现「我的代码模块化了,但依赖的老 jar 还留在 classpath」这种半吊子状态——要么把这些 jar 补上 Automatic-Module-Name 一起放进 module-path,要么整个应用先留在 classpath 别上。这直接决定了迁移是从外层包做起还是整体一起上,建议动手前先定好策略。

还有两点实操细节。--add-opens 是运行期参数,Maven 工程要在 surefire 的 argLine 和启动脚本里各配一份,只配一边就会出现测试全绿、启动即挂。maven-compiler-plugin 建议 3.11.0 以上,因为 3.7.0 起才会识别 module-info.java 并把依赖走模块路径。

最后一个建议:CI 里加一步 java --module-path mods --validate-modules,能在构建阶段就把模块冲突和缺失依赖打出来,不用等到线上启动那一刻。