provides 是 Java 9+ 模块系统中专用于 ServiceLoader 服务加载机制的声明指令,用于明确注册本模块对某服务接口的具体实现类,须与 uses 配合实现解耦调用。

provides 是 Java 9+ 模块系统中专用于 服务加载机制(ServiceLoader) 的声明指令,它的作用不是“提供变量”或“导出数据”,而是明确告诉 JVM:本模块实现了某个服务接口,并注册了具体实现类。它必须与 uses 配合使用,才能完成服务的解耦调用。
provides 的正确使用前提
要让 `provides` 生效,必须满足以下四个条件:
- 存在一个被导出(
exports)的公共服务接口,定义在独立的 API 模块中 - 实现类是 public、非 abstract、有无参构造器,且不能是匿名类或非 static 内部类
- 提供者模块在
module-info.java中通过provides 接口 with 实现类明确声明 - 使用者模块在
module-info.java中通过uses 接口表明“我将用 ServiceLoader 加载它”
标准三步落地流程
以日志服务为例,按模块职责拆分:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
1. 定义服务接口(API 模块:com.example.log.api)
module com.example.log.api { exports com.example.log.api; }
接口代码:
package com.example.log.api; public interface Logger { void log(String msg); }
2. 编写实现(实现模块:com.example.log.file)
module com.example.log.file { requires com.example.log.api; provides com.example.log.api.Logger with com.example.log.file.FileLogger; }
实现类:
package com.example.log.file; public class FileLogger implements Logger { public void log(String msg) { System.out.println("[FILE] " + msg); } }
3. 使用服务(应用模块:com.example.app)
module com.example.app { requires com.example.log.api; uses com.example.log.api.Logger; }
运行时加载:
ServiceLoader
关键细节提醒
这些地方容易出错,需特别注意:
立即学习“Java免费学习笔记(深入)”;
-
provides后必须写接口的**全限定名**,with后必须写实现类的**全限定名**,二者不可省略包名 - 实现模块无需
exports实现类所在的包——ServiceLoader 通过反射创建实例,不依赖编译期可见性 - 若多个模块都
provides同一接口,ServiceLoader.load()默认返回全部可用实现,可遍历或用findFirst()取第一个 - 使用者模块写
uses不会引入编译依赖,只启用运行时发现机制;没有uses,JVM 不会扫描该接口的提供者
常见误区澄清
别把 provides 当成配置工具或资源发布指令:
- ❌ 它不用于管理多语言文本、配置项、JSON 或 properties 文件
- ❌ 它不替代 Spring 的 @Service 或 CDI 的 @Produces
- ❌ 它不解决对象注入或依赖查找(如 ApplicationContext.getBean),只对接 ServiceLoader 标准 API
- ✅ 它解决的是:如何让模块 A 在不编译依赖模块 B 的前提下,运行时安全加载模块 B 提供的服务实现

















