在 Java 中,SPI(Service Provider Interface)全称为服务提供者接口,它是一种用于实现框架扩展和插件化的机制。
一、SPI 作用
二、基本原理
三、代码样例
1、定义服务接口
假设现在有一个权威机构,比如 Java,它需要对数据存储进行规范。
它定义了一个数据存储接口,和一个加载实现类的工具类。
package com.storage.specification;
/**
* 数据存储接口
*/
public interface StorageProvider {
void save(String data);
}
---------------------------------------------------
package com.storage.specification.spi;
import com.storage.specification.StorageProvider;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
/**
* 加载 存储服务 工具
*/
public class ProviderLoader {
public static StorageProvider getStorageProvider(ClassLoader classLoader) {
// 从类路径 resources/META-INF/services 下加载 存储服务提供者
ServiceLoader<StorageProvider> loader = ServiceLoader.load(StorageProvider.class, classLoader);
Iterator<StorageProvider> iterator = loader.iterator();
List<StorageProvider> providers = new ArrayList<>();
while (iterator.hasNext()) {
providers.add(iterator.next());
}
return providers.get(0);
}
}
2、实现服务接口
现在有两个供应商 Mysql 和 Redis,它们拿到 Java 给的规范,分别提供他们的 二进制文件 存储实现和内存数据库实现。
Mysql 实现:
以同样的方式创建一个 Redis 项目,取名 redis-storage-provider
3、定义服务使用者
1)用 IDEA 新建一个 maven 项目,取名叫 storage-user
2)pom 依赖引入 规范 gav 和 mysql gav
<dependencies>
<dependency>
<groupId>com.storage.specification</groupId>
<artifactId>storage-specification</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.mysql.storage</groupId>
<artifactId>mysql-storage-provider</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
3) 调用 mysql 存储
4)切换 redis 依赖
<dependencies>
<dependency>
<groupId>com.storage.specification</groupId>
<artifactId>storage-specification</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.redis.storage</groupId>
<artifactId>redis-storage-provider</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
5)调用 redis 存储
可以看到,我们只修改了依赖的实现包,并没有修改代码,就实现了服务的替换。
而且我们的代码中并没有显示地调用服务的实现类。
四、总结