Java SPI(Service Provider Interface)示例
Java SPI(Service Provider Interface)是一种服务发现机制,允许第三方为接口提供实现,实现解耦和动态扩展。核心流程:
- 定义服务接口
- 提供接口实现(可多个)
- 注册实现(在
META-INF/services中配置) - 通过
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!
关键点说明
- 服务注册文件位置
META-INF/services/接口全限定名(无文件后缀) - 文件内容格式
每行一个实现类的全限定名(如多实现需换行) - 加载原理
ServiceLoader通过线程上下文类加载器查找所有META-INF/services下的注册信息 - 应用场景
- JDBC驱动加载(
DriverManager) - SLF4J日志门面
- Spring Boot自动配置
- JDBC驱动加载(
对比普通接口调用
| 方式 | SPI机制 | 普通接口调用 |
|---|---|---|
| 耦合度 | 实现类可独立扩展,完全解耦 | 需显式依赖具体实现 |
| 新增实现 | 添加JAR包即生效 | 需修改调用方代码 |
| 依赖关系 | 调用方只依赖接口 | 调用方依赖接口+具体实现 |
提示:在Spring Boot中,
spring.factories机制是SPI的增强版,原理类似但支持更复杂的自动配置场景。
浙公网安备 33010602011771号