Java 9模块系统用module-info.java的uses/provides替代META-INF/services,实现编译期类型安全的服务契约声明;服务方需public无参构造,双方必须严格匹配全限定名且正确requires接口模块。
java 9 引入的模块系统(jpms)对传统 spi 机制做了实质性升级:不再依赖 meta-inf/services/xxx 手动配置文件,而是通过 module-info.java 中的 uses / provides 指令,在编译期声明服务契约,由 jvm 在运行时自动完成类型安全的服务发现与绑定。这种替代不是简单“换写法”,而是从字符串驱动转向模块化、可验证、可裁剪的服务治理方式。
module-info.java 中服务声明的规范写法
服务使用方和提供方需在各自模块中明确声明角色,JVM 会据此建立强类型关联:
-
服务使用者模块(如客户端)必须用
uses声明它要消费的服务接口module com.example.client { requires com.example.api; uses com.example.api.GreetingService; // 告诉 JVM:我要用这个接口 } -
服务提供者模块(如国密实现)必须用
provides ... with ...声明具体实现类module com.example.sm4impl { requires com.example.api; provides com.example.api.GreetingService with com.example.sm4.SM4GreetingServiceImpl; // 实现类必须是 public & 无参构造 }
注意:
provides后的实现类必须满足两个硬性条件——类是public的,且有public无参构造器;否则模块加载失败或ServiceLoader返回空迭代器。立即学习“Java免费学习笔记(深入)”;
java-api-doc-generator下载分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
如何让 ServiceLoader 正常工作在模块化环境
模块化下 ServiceLoader.load() 行为不变,但底层依赖模块图解析而非 classpath 扫描。因此必须确保:
- 接口定义模块(如
com.example.api)被双方共同requires,且该模块不包含provides或uses(仅作契约容器) - 消费端模块的
uses和提供端模块的provides必须严格匹配全限定名(大小写、包路径、类名缺一不可) - 若使用
--limit-modules或 jlink 构建最小运行镜像,需显式包含所有参与服务发现的模块(含java.base)
常见失效情形举例:
- 提供方模块未
requires接口模块 → 编译报错package not visible - 消费方漏写
uses→ServiceLoader.load(...).iterator()返回空,无任何异常提示 - 实现类位于非默认包或含嵌套结构 →
ServiceLoader无法实例化,抛ServiceConfigurationError
与传统 META-INF/services 的关键差异点
| 维度 | 传统 SPI(classpath) | JPMS 模块化 SPI |
|---|---|---|
| 配置位置 |
META-INF/services/com.example.api.GreetingService(纯文本,内容为实现类全名) |
module-info.java 中 uses/provides(Java 语法,编译期校验) |
| 类型安全 | 无。拼写错误、类不存在、无参构造缺失均到运行时报错 | 有。编译阶段即检查接口是否存在、实现类是否可访问、构造器是否合规 |
| 模块可见性 | 所有 jar 下同名文件都会被扫描,易冲突或重复加载 | 仅模块图中显式 provides 的模块参与,无隐式加载,避免污染 |
| 服务筛选 | 无法按模块来源过滤,ServiceLoader 返回全部可用实现 |
可结合 ModuleLayer 自定义层策略,实现灰度、多租户等高级路由 |
例如在信创环境中集成 SM4 加解密服务:
- 定义统一接口模块
crypto.api(只含SM4Cipher接口) - 国密厂商提供
crypto.sm4.bisun模块,provides crypto.api.SM4Cipher with bisun.SM4Impl - 应用模块
app.secureuses crypto.api.SM4Cipher并requires crypto.api - 运行时只需替换模块路径中的
crypto.sm4.bisun.jar为crypto.sm4.loongarch.jar,无需改任何配置文件或代码
不复杂但容易忽略



















