SPI 是什么?
SPI(Service Provider Interface)是一种 服务发现机制,它允许应用在 运行时 动态地查找和加载服务实现,而 无需在编译时显式指定具体实现类。
在 Android(以及 Java)中,SPI 主要用于解耦模块,使框架可以通过配置文件动态加载实现类。
SPI 的核心概念
服务接口(Service Interface)
一个公共接口或抽象类,定义服务规范,由不同的实现类提供具体实现。
服务提供者(Service Provider)
具体的实现类,实现了 Service Interface,并通过 META-INF/services 文件注册。
服务加载器(ServiceLoader)
通过 java.util.ServiceLoader 进行服务发现和加载,实现解耦。
🔧 SPI 在 Android 中的使用
1、定义服务接口
public interface IAudioPlayer {
void play(String filePath);
}
2、提供实现类
public class DefaultAudioPlayer implements IAudioPlayer {
@Override
public void play(String filePath) {
Log.d("AudioPlayer", "播放音乐:" + filePath);
}
}
3、在 META-INF/services/ 目录下创建文件
创建 META-INF/services/com.example.IAudioPlayer(文件名是接口的完整路径),内容如下:
com.example.DefaultAudioPlayer
4、通过 ServiceLoader 加载实现
ServiceLoader<IAudioPlayer> serviceLoader = ServiceLoader.load(IAudioPlayer.class);
for (IAudioPlayer player : serviceLoader) {
player.play("music.mp3");
}
SPI 在 Android 中的应用
Glide 图片加载框架
使用 SPI 发现和加载 com.bumptech.glide.integration.okhttp3.OkHttpGlideModule 等模块。
Room 持久化数据库
Room 通过 ServiceLoader 发现 androidx.room.RoomDatabase$Builder 的实现类。
Navigation 组件
Android Jetpack Navigation 也使用了 SPI 机制来动态加载 NavigatorProvider。
SPI 在 Android 的局限
反射开销:SPI 依赖 ServiceLoader,本质上是 反射 加载类,可能影响性能。
ProGuard 规则:混淆时,可能会导致 META-INF/services/ 目录下的文件丢失,需要手动配置 ProGuard 规则:
-keep class com.example.DefaultAudioPlayer { *; }
总结
SPI 是 Java & Android 的一种 服务发现机制,用于动态加载实现类。
通过 ServiceLoader 在运行时查找 META-INF/services 下的实现类,减少代码耦合。
在 Glide、Room、Navigation 等 Jetpack 组件中被广泛使用。
由于 反射 的存在,在性能敏感的场景(如 Android)下,需要谨慎使用。