Java SPI机制通过ServiceLoader实现面向接口的多态加载,依赖META-INF/services下按接口全限定名命名的配置文件声明实现类,运行时按需加载并实例化,体现延迟加载、类加载器敏感及非线程安全特性。

Java SPI(Service Provider Interface)机制通过 ServiceLoader 实现基于接口的多态加载,核心在于“面向接口编程 + 运行时动态发现实现类”。它不依赖硬编码 new 或 Spring 的 Bean 容器,而是靠约定目录结构和配置文件,在类路径下自动扫描并实例化符合接口的实现。
接口定义与实现类分离
先定义一个标准接口,所有插件或扩展都必须实现它。例如:
public interface DataProcessor {
String process(String input);
}
不同模块提供各自实现,比如:
JsonProcessor implements DataProcessorXmlProcessor implements DataProcessor
这些实现类彼此独立,甚至可以打在不同 jar 包里,只要遵循 SPI 规范即可被统一加载。
立即学习“Java免费学习笔记(深入)”;
META-INF/services 配置文件驱动发现
ServiceLoader 不靠反射扫描全类路径,而是读取 META-INF/services/接口全限定名 文件。例如,创建文件:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
META-INF/services/com.example.DataProcessor
内容为具体实现类的全限定名,一行一个:
com.example.JsonProcessor com.example.XmlProcessor
这个文件必须放在实现类所在 jar 的 META-INF/services/ 目录下。JVM 启动时不会加载它们,ServiceLoader.load() 调用时才按需读取并实例化。
ServiceLoader 加载与多态调用
使用方式简洁,体现多态本质:
ServiceLoader<DataProcessor> loader = ServiceLoader.load(DataProcessor.class);
for (DataProcessor processor : loader) {
System.out.println(processor.process("hello")); // 运行时决定调用哪个实现
}
这里 processor 是接口类型,但实际执行的是 JsonProcessor.process() 或 XmlProcessor.process() —— 典型的运行时多态。每次迭代拿到的都是新实例(ServiceLoader 默认每次 next() 创建新对象),无需手动 new 或判断类型。
注意点:延迟加载、线程安全与 ClassLoader
ServiceLoader 是懒加载的,load() 只构建加载器,真正解析配置和实例化发生在首次遍历时。它使用当前线程上下文类加载器(Thread.currentThread().getContextClassLoader())查找资源,因此跨模块或容器环境(如 Tomcat、OSGi)中需确保该类加载器能访问到 META-INF/services 文件。默认不保证线程安全,多线程并发遍历同一 ServiceLoader 实例需自行同步。

















