发布于2026-07-11 阅读(0)
扫一扫,手机访问
一句话总结:靠 exports 控制包可见性 + requires 精确声明依赖 + 避免 open module,就能实现二方库的强隔离;漏掉任一环节,反射、类加载或跨模块调用都可能绕过封装。

上面那个框就是核心原则。但现实是,很多人以为写了 module-info.ja va 就算模块化了,结果运行时问题百出——反射、类加载、跨模块调用,哪个都能把封装撕个口子。关键在于,每一行声明都得经得起推敲。
二方库(比如内部通用工具包 com.example.utils)想只暴露 API,就必须显式导出接口包,同时禁止导出实现包。常见错误是:导出整个模块名、写错包路径、或者误用通配符——JPMS 根本不认 exports com.example.* 这种写法。
exports com.example.utils.api; ✅ 只让外部看到接口定义exports com.example.utils; ❌ 把 impl、internal 全暴露了exports com.example.utils.internal; ❌ 内部包不应对外可见exports 的任何包,默认不可被其他模块访问,即使类是 public二方库依赖 ja va.logging 或 com.example.core 时,requires 要严格按实际使用范围写。滥用 transitive 会带来连锁反应——下游模块意外获得不该有的可读性,隔离边界就形同虚设。
requires ja va.logging; ✅ 仅当前模块可用日志requires transitive ja va.logging; ❌ 强制下游也“可读”日志模块,扩大攻击面uses com.example.spi.Service,而非 requires 实现模块jdk.unsupported)的依赖要彻底删除,它们在 JDK 17+ 已被移除二方库打成模块化 JAR 后,若下游项目仍用 --class-path 启动,JVM 会把它降级为“自动模块”,此时 exports 直接失效,所有 public 类又变回全局可见——强隔离瞬间归零。这个坑最常见,也最容易忽略。
ja va --module-path lib/ --module myapp/com.example.Main,不能夹带 -cpjdeps --module-path lib/ --summary myapp.jar,输出中含 unnamed module 或 automatic module 即为风险点utils-1.2.0.jar → utils),易与真实模块名冲突,建议统一重命名并补全 Automatic-Module-Name MANIFEST 属性Spring、Hibernate 这些框架常因为反射失败报 IllegalAccessError。但很多人第一反应就是往 module-info.ja va 里加 opens com.example.utils.config to spring.core,甚至直接写成 open module——这等于主动拆了隔离墙。
exports 包下,或者提供工厂方法代替反射实例化opens com.example.utils.config to ja va.desktop(仅限 Ja vaFX 场景)opens 不继承,opens com.example.utils.config 不代表其子包自动开放--illegal-access=deny),此时 opens 是唯一合规解法,但务必限定目标模块强隔离真正的难点不在语法,而在组织习惯:每个 requires 都得有业务依据,每个 exports 都得经 API 评审,而构建脚本里一个 --class-path 就能让所有设计失效。模块系统不替你做决策,它只确保你写的每行声明,都会在运行时被严格执行。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8