Java SPI(ServiceLoader)机制与实现原理
解释Java SPI(Service Provider Interface)机制的工作流程,包括ServiceLoader的加载原理、META-INF/services配置文件的规范、延迟加载的实现以及SPI与API的区别。
回答
小字辈
1. SPI工作流程
调用方 → ServiceLoader.load(接口.class) → 读取META-INF/services/配置
→ 反射实例化实现类 → 返回迭代器
关键步骤:
- 定义接口(SPI接口)
- 提供方实现接口
- 在
META-INF/services/接口全限定名文件中写入实现类全限定名 - 调用方通过
ServiceLoader.load()加载
2. SPI示例
// 1. 接口
public interface Search {
List<String> search(String keyword);
}
// 2. 实现
public class DatabaseSearch implements Search {
public List<String> search(String keyword) {
return ...;
}
}
// 3. 配置文件 META-INF/services/com.example.Search
// 内容: com.example.impl.DatabaseSearch
// 4. 使用
ServiceLoader<Search> loader = ServiceLoader.load(Search.class);
for (Search search : loader) {
search.search("Java");
}
3. ServiceLoader原理
- 内部使用懒加载(LazyIterator),调用
next()时才真正加载 - 缓存已加载的实例(reload()可重新加载)
- ClassLoader决定搜索路径的classpath
- 实现
Iterable接口,支持foreach语法 - 使用线程上下文类加载器(TCCL)解决跨模块加载
4. SPI vs API | 特性 | API | SPI | |------|------|------| | 控制方 | 调用方定义接口 | 服务方定义接口 | | 调用方向 | 调用方→实现方 | 实现方→调用方 | | 扩展方式 | 调用方选择实现 | 服务方发现实现 | | 典型应用 | JDBC Driver | java.sql.Driver |