uses声明用于Java 9+模块系统中表明当前模块使用某服务接口,须与requires配合写在module-info.java中,仅表达需求而不绑定实现,为ServiceLoader提供元数据支持。

uses 声明用于在 Java 9+ 的模块系统中表明当前模块“使用”某个服务接口,即它会在运行时通过 ServiceLoader.load() 主动查找并加载该服务的实现。它不提供实现,也不声明依赖具体提供者,只表达“我需要这个服务”的意图。
uses 声明的作用和位置
它写在 module-info.java 的 uses 子句中,必须配合 requires(导入服务接口所在的模块)一起使用。JVM 会据此在模块路径上查找所有声明了 provides ... with ... 的模块,并加载其实现类。
- 仅声明“我要用”,不绑定具体实现
- 必须与
requires同时存在,否则编译报错(因为接口类型需可见) - 一个模块可声明多个
uses,也可多次声明同一服务(无意义但合法)
基本写法示例
假设你开发一个日志客户端模块 com.example.logger.client,想通过 ServiceLoader 使用 com.example.logging.LoggerService 接口:
module com.example.logger.client {
requires com.example.logging.api; // 提供 LoggerService 接口的模块
uses com.example.logging.LoggerService;
}
此时你的代码中可以安全调用:
立即学习“Java免费学习笔记(深入)”;
ServiceLoader<LoggerService> loader = ServiceLoader.load(LoggerService.class);
loader.forEach(logger -> logger.log("Hello from client")); // 自动发现并加载实现
注意事项和常见问题
uses 不触发自动模块解析或强制加载提供者模块——它只是为 ServiceLoader 提供元数据支持。真正加载实现在运行时发生,且要求:
- 提供者模块必须在模块路径上(而非类路径)
- 提供者模块的
module-info.java中必须有对应provides ... with ...声明 - 服务接口类型必须对使用者模块可见(所以
requires不可省略) - 若多个模块提供了同一服务,
ServiceLoader按模块读取顺序返回实例(无固定优先级)
与 requires 和 provides 的关系
三者协同构成服务使用闭环:
-
requires:让接口类型可用(编译/运行时类型依赖) -
uses:告诉 JVM “我会调用ServiceLoader.load(Interface.class)” -
provides(在另一模块中):告诉 JVM “我实现了这个接口,可被自动发现”
缺少 uses,ServiceLoader.load() 仍能工作(尤其在非模块化环境),但在严格模块图验证(如 --validate-modules)下可能被警告;加上它,能让模块系统更准确理解服务消费关系,提升可维护性和工具支持能力。


















