serviceloader通过spi机制动态加载接口实现类,核心是jvm按约定路径meta-inf/services/接口全限定名扫描配置文件,反射实例化其中声明的public实现类(需无参构造),实现解耦与可扩展。

Java 中接口通过 ServiceLoader SPI 机制动态加载实现类,核心是“约定优于配置”:接口不硬编码实现类,而是由 JVM 在运行时按标准路径扫描并加载 META-INF/services/接口全限定名 文件中声明的实现类。
定义服务接口(必须是 public 接口)
接口本身不需要特殊注解或继承,但必须是 public 的,且通常不包含默认方法(除非明确需要共享逻辑):
public interface DataProcessor {
String process(String input);
}注意:接口不能是内部类、private 或 package-private,否则 ServiceLoader 无法访问。
编写实现类并确保可被发现
实现类需满足三个条件:
- 实现该接口(如
class JsonProcessor implements DataProcessor) - 声明为
public - 提供无参构造函数(
ServiceLoader使用反射调用Class.getDeclaredConstructor().newInstance())
例如:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
public class JsonProcessor implements DataProcessor {
@Override
public String process(String input) {
return "JSON: " + input;
}
}在 JAR 的 META-INF/services 下声明服务提供者
在实现类所在的 JAR 包(或 classpath 路径)中,创建文件:
META-INF/services/com.example.DataProcessor文件内容为实现类的**全限定名**,一行一个:
com.example.JsonProcessor com.example.XmlProcessor
⚠️ 注意:
- 文件名必须是接口的完整类名(包名+类名),不能拼错;
- 文件编码为 UTF-8,BOM 会导致类名解析失败;
- 多个实现类可共存,ServiceLoader 会全部加载。
运行时加载并使用实现类
使用 ServiceLoader.load(接口.class) 获取迭代器,遍历调用:
ServiceLoader<dataprocessor> loader = ServiceLoader.load(DataProcessor.class);
for (DataProcessor processor : loader) {
System.out.println(processor.process("hello"));
}</dataprocessor>常见用法补充:
- 可通过
loader.iterator().hasNext()判断是否有可用实现 - 推荐配合
Optional或 try-with-resources(ServiceLoader实现了Iterable,但不实现AutoCloseable) - 若只想要第一个可用实现,可用
loader.findFirst()(Java 11+) - 加载失败(如类找不到、无参构造异常)会在遍历时抛出
ServiceConfigurationError,建议捕获处理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










