Java 9模块系统通过uses声明服务需求、provides with注册服务实现,配合独立SPI模块解耦接口与实现,运行时由ServiceLoader自动加载匹配的实现类。

Java 9 模块系统通过 uses 和 provides 关键字实现服务接口的声明与绑定,这是模块间松耦合通信的核心机制。
在使用者模块中声明“需要什么服务”
如果一个模块要调用某个服务接口(比如 PaymentProcessor),但不关心具体实现,就在它的 module-info.java 中用 uses 声明:
uses com.example.payment.spi.PaymentProcessor;- 这表示该模块会在运行时通过
ServiceLoader.load(PaymentProcessor.class)加载实现类 - 注意:
uses不引入编译依赖,只表达“我打算用这个接口”
在提供者模块中声明“我实现了什么服务”
另一个模块若提供了该接口的具体实现(如 AlipayProcessor),需在自己的 module-info.java 中用 provides…with 显式注册:
provides com.example.payment.spi.PaymentProcessor with com.example.alipay.AlipayProcessor;- 必须确保
AlipayProcessor类实现了该接口,并且所在包已被exports - 一个接口可被多个模块分别
provides,运行时按模块路径顺序加载
服务接口本身应放在独立模块中
推荐将服务接口定义在单独的模块(如 payment-spi)里,便于解耦:
立即学习“Java免费学习笔记(深入)”;
- 该模块只需
exports接口所在的包,不包含实现 - 使用者模块和提供者模块都
requires payment-spi - 避免循环依赖,也方便替换实现(如从支付宝换成微信支付)
运行时加载服务的典型写法
在使用者模块的代码中,直接使用标准 ServiceLoader:
ServiceLoader<PaymentProcessor> loader = ServiceLoader.load(PaymentProcessor.class);- 遍历
loader获取可用实现,无需硬编码类名或反射 - 模块系统会自动扫描所有已解析模块中匹配的
provides声明


















