requires transitive 的核心是精准导出依赖:仅当第三方类型出现在 public API 签名中(如参数、返回值、异常类型)时才需声明,否则用普通 requires 或不声明;exports 也须严格限定为 api 包。

要通过 requires transitive 构建一个真正好用的通用变量工具包,核心不是堆功能,而是精准控制“谁该看到什么”。它得让使用者开箱即用,不报 NoClassDefFoundError,也不被一堆冗余依赖拖累。
明确工具包的定位和导出边界
先想清楚:这个工具包是给谁用的?提供的是 API 还是纯内部工具?
- 如果只封装了几个静态方法(比如
Vars.of(String...)),且返回类型全是java.base里的(Map、List、String),那根本不需要transitive——这些类型本就全局可见 - 如果工具包公开了一个接口
VariableResolver,而这个接口的某个方法签名用了com.fasterxml.jackson.databind.JsonNode作为参数或返回值,那就必须requires transitive com.fasterxml.jackson.databind - 导出包要克制:只
exports com.example.vars.api;,别把impl或internal包也导出来
合理声明 transitive 依赖,只传递真正暴露的类型
假设你的工具包提供了 JSON 变量解析能力,并对外暴露了带 Jackson 类型的方法:
package com.example.vars.api;
import com.fasterxml.jackson.databind.JsonNode;
public interface JsonVarReader {
JsonNode readFrom(String key); // 返回类型来自 jackson
}
对应 module-info.java 就该这样写:
module com.example.vars {
requires java.base;
requires transitive com.fasterxml.jackson.databind; // ✅ 必须 transitive
requires transitive java.logging; // ✅ 若 Logger 是 public 方法的参数/返回值类型
requires org.slf4j; // ❌ 普通 requires 即可(仅内部桥接使用)
exports com.example.vars.api;
}
注意:org.slf4j 如果只是你在 impl 里偷偷用 SLF4J 做日志,没出现在任何 api 包的签名中,就绝不能加 transitive——否则下游项目会被强制引入 SLF4J,可能引发绑定冲突。
下游模块接入时零配置负担
当另一个业务模块依赖你的工具包时,它能直接使用传递来的类型,无需重复声明:
// module com.example.order
module com.example.order {
requires com.example.vars; // 只写这一行就够了
}
// 在代码里可直接用:
JsonVarReader reader = ...;
JsonNode node = reader.readFrom("config"); // ✅ 编译通过,无需 requires jackson
Logger logger = Logger.getLogger("order"); // ✅ 也可直接用 java.logging
这就是 requires transitive 的实际价值:它把“调用方必须知道的依赖”从文档移到了编译系统里,由 JVM 和构建工具自动保障。
避免常见陷阱:测试依赖、SPI、内部实现别污染
这几个地方最容易误用 transitive:
-
测试依赖:JUnit、AssertJ 等永远用普通
requires,甚至应放在test源集里,绝不进module-info.java -
SPI 服务加载:如果你通过
ServiceLoader.load(VariableProvider.class)加载插件,而VariableProvider在你自己的api包里,那插件模块只需requires你的模块;你不需要对插件所依赖的模块做transitive -
内部实现类引用第三方类型:比如你在
impl.DefaultVarStore里用了org.apache.commons.text.StringSubstitutor,但这个类完全不出现在api中,那就只requires org.apache.commons.text,不加transitive


















