Java SPI(Service Provider Interface)示例

Java SPI(Service Provider Interface)是一种服务发现机制,允许第三方为接口提供实现,实现解耦动态扩展。核心流程:

  1. 定义服务接口
  2. 提供接口实现(可多个)
  3. 注册实现(在META-INF/services中配置)
  4. 通过ServiceLoader加载服务

完整示例

1. 定义接口

// 文件路径: src/main/java/com/example/LogService.java
package com.example;

public interface LogService {
    void log(String message);
}

2. 实现接口(两个不同实现)

// 文件路径: src/main/java/com/example/ConsoleLogger.java
package com.example;

public class ConsoleLogger implements LogService {
    @Override
    public void log(String message) {
        System.out.println("[Console] " + message);
    }
}
// 文件路径: src/main/java/com/example/FileLogger.java
package com.example;

public class FileLogger implements LogService {
    @Override
    public void log(String message) {
        System.out.println("[File] Log saved: " + message); // 模拟写入文件
    }
}

3. 注册服务实现

在资源目录创建文件:
src/main/resources/META-INF/services/com.example.LogService
内容为实现类的全限定名

com.example.ConsoleLogger
com.example.FileLogger

4. 使用服务

// 文件路径: src/main/java/com/example/MainApp.java
package com.example;

import java.util.ServiceLoader;

public class MainApp {
    public static void main(String[] args) {
        // 加载所有LogService实现
        ServiceLoader<LogService> loggers = ServiceLoader.load(LogService.class);
        
        // 遍历并调用服务
        for (LogService logger : loggers) {
            logger.log("Hello SPI!");
        }
    }
}

运行结果

[Console] Hello SPI!
[File] Log saved: Hello SPI!

关键点说明

  1. 服务注册文件位置
    META-INF/services/接口全限定名(无文件后缀)
  2. 文件内容格式
    每行一个实现类的全限定名(如多实现需换行)
  3. 加载原理
    ServiceLoader通过线程上下文类加载器查找所有META-INF/services下的注册信息
  4. 应用场景
    • JDBC驱动加载(DriverManager
    • SLF4J日志门面
    • Spring Boot自动配置

对比普通接口调用

方式 SPI机制 普通接口调用
耦合度 实现类可独立扩展,完全解耦 需显式依赖具体实现
新增实现 添加JAR包即生效 需修改调用方代码
依赖关系 调用方只依赖接口 调用方依赖接口+具体实现

提示:在Spring Boot中,spring.factories机制是SPI的增强版,原理类似但支持更复杂的自动配置场景。

posted @ 2025-06-24 09:48  许仙儿  阅读(39)  评论(0)    收藏  举报