Java 9模块系统通过uses声明服务消费、provides...with声明服务提供,实现编译期验证的SPI机制;服务接口模块需无限制导出接口包,消费者模块用uses声明依赖,提供者模块用requires和provides...with绑定实现类。

Java 9 模块系统中声明服务实现,关键在于配合 uses(消费)和 provides ... with(提供)两条语句,形成标准的 SPI(Service Provider Interface)机制。它不是靠类路径自动发现,而是由模块显式声明“我用什么服务”和“我提供什么服务”,编译期即可验证,避免运行时 ServiceConfigurationError。
服务接口模块:必须无限制导出接口包
定义 SPI 的模块(如 app.view)需将服务接口所在包完整导出,且不加 to 限制,否则第三方实现模块无法访问该接口:
-
exports app.view;✅ 允许任意模块看到View接口 -
exports app.view to app.core;❌ 第三方模块无法实现,违反开闭原则
服务消费者模块:用 uses 声明依赖的服务类型
调用方模块(如主应用 app)需在 module-info.java 中声明它要通过 ServiceLoader 加载哪些服务:
-
uses app.view.View;—— 表示本模块会在运行时调用ServiceLoader.load(View.class) - 这条语句不引入编译依赖,只起元数据作用;但若对应服务未被任何模块提供,
jlink或运行时可能报错
服务提供者模块:用 provides ... with 绑定具体实现类
真正实现服务的模块(如 com.example.myview)必须:
立即学习“Java免费学习笔记(深入)”;
- 声明对服务接口模块的依赖:
requires app.view; - 用
provides明确告知 JVM:“我实现了app.view.View,具体是MyViewImpl类”:provides app.view.View with com.example.myview.MyViewImpl; - 注意:
MyViewImpl所在包无需导出,只要类是 public、有无参构造器即可
运行时加载服务的代码保持不变
业务代码仍使用标准 ServiceLoader,模块系统自动按声明完成发现:
ServiceLoader<View> loader = ServiceLoader.load(View.class);<br>loader.forEach(view -> view.render());


















