requires static 是 Java 9 模块系统中声明编译期依赖的修饰符,仅影响模块解析与可达性检查,不参与运行时对象创建或依赖注入;它支持测试时静态引用 Mock 类型,但需配合接口抽象、模块分层及构造器传参等传统方式实现 Mock 注入。

requires static 是 Java 9 引入的模块系统(JPMS)中 requires 指令的一个修饰符,用于声明对另一个模块的**静态依赖**——即该依赖仅在编译期和链接期需要,运行时可选、甚至可以不存在。它本身**不直接支持“在测试环境注入 Mock 变量”**,也不能像 Spring 的 @MockBean 或 Mockito 的 mock() 那样动态替换对象。但你可以结合模块化设计、接口抽象与测试策略,**间接实现“测试时使用 Mock 实现、生产时使用真实实现”的模块级隔离**。
明确 requires static 的真实作用
它只影响模块图解析和 JVM 启动时的模块可达性检查,不参与运行时对象创建或依赖注入。例如:
module myapp.service {
requires static org.mockito; // 编译时可用 Mockito 类型,运行时不需 org.mockito 模块
exports com.myapp.service.api;
}
这样写后,你可以在模块内写 import static org.mockito.Mockito.*;,但打包运行时不必包含 mockito-core 模块——适合写测试工具类,但不是用来“引入 Mock 变量”的机制。
真正可行的实战路径:接口 + 模块分层 + 测试模块覆盖
要达成“测试用 Mock、运行用真实”,核心是解耦实现与使用,再通过模块依赖控制可见性:
-
定义稳定 API 模块(如
myapp.api):只含接口(UserService)、DTO、常量,无实现,不依赖任何第三方 -
实现模块分离:
-
myapp.service.impl:提供真实实现,requires myapp.api -
myapp.service.mock:提供轻量 Mock 实现(如MockUserService),也requires myapp.api
-
-
主应用模块选择性依赖:
- 生产
module myapp.main:只requires myapp.service.impl - 测试模块
module myapp.test:requires myapp.api; requires static myapp.service.mock;(静态依赖确保编译通过,但测试启动时才加载 mock 模块)
- 生产
测试中实际注入 Mock 实现的推荐方式
模块系统不管理对象生命周期,所以仍需传统手段完成“注入”:
- 构造器/方法参数传入:在测试中 new MockUserService(),传给被测类构造器
-
ServiceLoader + 模块声明:在
META-INF/services/com.myapp.api.UserService中,测试模块里放com.myapp.mock.MockUserService,生产模块里放真实类;测试时用ServiceLoader.load(UserService.class)自动发现 Mock 类 -
System.setProperty 或配置开关:启动测试时加
-Dservice.mode=mock,代码中根据属性决定 new 哪个实现(需模块内能访问两者,此时requires static可让 mock 模块仅编译期可见)
一个最小可运行示例结构
目录示意(使用 jlink 或 jmod 打包):
src/
├── myapp.api/
│ └── module-info.java // module myapp.api { exports com.myapp.api; }
├── myapp.service.impl/
│ └── module-info.java // module myapp.service.impl { requires myapp.api; }
├── myapp.service.mock/
│ └── module-info.java // module myapp.service.mock { requires myapp.api; }
└── myapp.test/
└── module-info.java // module myapp.test { requires static myapp.api; requires static myapp.service.mock; }
测试类中直接 new MockUserService() 使用,无需反射或框架——因为 requires static 已让编译器认可该类型存在,而 JVM 运行测试时会自动解析并加载 myapp.service.mock 模块。

















