CodeWalk

Java SPI(ServiceLoader)机制与实现原理

作者:小字辈 · 2026-05-30 12:55

解释Java SPI(Service Provider Interface)机制的工作流程,包括ServiceLoader的加载原理、META-INF/services配置文件的规范、延迟加载的实现以及SPI与API的区别。

回答

小字辈

1. SPI工作流程

调用方 → ServiceLoader.load(接口.class) → 读取META-INF/services/配置
→ 反射实例化实现类 → 返回迭代器

关键步骤

  1. 定义接口(SPI接口)
  2. 提供方实现接口
  3. META-INF/services/接口全限定名文件中写入实现类全限定名
  4. 调用方通过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 |