关键在于理解module-info.java中声明的实际作用边界:exports控制编译期类型引用,opens专管反射权限,requires声明依赖,transitive解决传递性断裂;module-info.java必须置于src/main/java根目录,否则报“module not found”。
掌握 java 模块化系统的变量可见性控制,关键不在写多少代码,而在于理解 module-info.java 中每一行声明的实际作用边界——它不决定“能不能用”,而是决定“谁在什么条件下能用”。真正有效的实战,是从一个最小可运行模块开始,逐步叠加 exports、opens、requires 和 transitive,观察编译期报错、运行时异常和反射行为的差异。
第一步:创建合法模块结构,避免“模块未找到”陷阱
module-info.java 必须放在 src/main/java/ 目录下,与任何包文件夹(如 com/)平级。常见错误包括:
- 把它放进
src/main/java/com/example/—— 编译器会当成普通类,报error: module not found - 用 IDE 自动生成却没检查路径 —— IntelliJ 有时默认建在子包内,需手动剪切到根目录
- Maven 项目中未设置编译版本:必须在
pom.xml的maven-compiler-plugin中指定<release>11</release>或更高
第二步:用 exports 控制编译期可见性
仅把类声明为 public 不足以让其他模块访问。例如:
你有一个 com.example.util.StringUtils 类,想被别的模块调用:
- 在
module-info.java中加exports com.example.util; - 消费方模块必须写
requires your.module.name; - 若漏掉
exports,即使类是 public,编译时也会报package com.example.util is not visible
注意:exports 只影响编译期类型引用和运行时类加载,不影响反射。
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
立即学习“Java免费学习笔记(深入)”;
第三步:用 opens 精准开放反射权限
当 JSON 库(如 Jackson)或 ORM(如 Hibernate)需要读写私有字段时,exports 无效,必须用 opens:
-
opens com.example.model;:允许任意模块通过反射访问该包内所有类的私有成员 -
opens com.example.model to com.fasterxml.jackson.databind;:只允许 Jackson 模块反射访问,更安全 - 若只写
exports不写opens,反序列化会抛IllegalAccessException
第四步:用 requires transitive 解决传递依赖断裂
假设你的模块 A 依赖模块 B,而 B 内部用了 java.sql 并导出了相关类型。如果 A 想直接使用这些类型:
- B 的
module-info.java中写了requires java.sql;,但没加transitive - A 就无法直接引用
java.sql.Connection,编译报错 - 修复方式:B 改为
requires transitive java.sql;,A 就能“透传看到” - Spring Boot 3+ 默认要求模块化兼容,漏写
transitive是NoClassDefFoundError的高频原因
不复杂但容易忽略


















