SPI机制
Java SPI思想梳理
1.看了一些spi机制相关的文章,尝试写出自己的理解,不正确的地方欢迎指出。
java的spi机制,相对于api机制;
- api机制:模块之间依赖接口而不依赖具体的实现,具体的实现类的修改不影响接口的使用。而调用方不需要关心接口的具体实现是什么,只需要知道自己需要什么能力即可。
- spi机制:提供方制定了接口,并事先准备好多套实现;使用方来决定使用哪种实现。
2 SPI具体约定
java spi的具体约定为:当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。jdk提供服务实现查找的一个工具类:java.util.ServiceLoader
java.util.ServiceLoader使用
Java.util.ServiceLoader这个类来从配置文件中加载子类或者接口的实现类。以前从来没有使用过这个类,进去大概看了一下具体的实现。主要是从META-INF/services这个目录下的配置文件加载给定接口或者基类的实现,ServiceLoader会根据给定的类的full name来在META-INF/services下面找对应的文件,在这个文件中定义了所有这个类的子类或者接口的实现类,返回一个实例。
首先定义接口
public interface Search {
public List<String> search(String keysord);
}
两个实现类
public class DocSearch implements Search {
@Override
public List<String> search(String keysord) {
System.out.println("dearch in doc");
return null;
}
}
public class DbSearch implements Search {
@Override
public List<String> search(String keysord) {
System.out.println("db search");
return null;
}
}
然后 在META-INF/services目录下新建文件:
spi.Search
文件内容为:实现类的全路径
#写上Search接口的实现类,这样就可以知道调用哪个实现类了
spi.DocSearch
spi.DbSearch
测试一下:
public class Test {
public static void main(String[] args) {
//加载到spi.Search文件下面配置的实现类
ServiceLoader<Search> s = ServiceLoader.load(Search.class);
Iterator<Search> iterator = s.iterator();
while (iterator.hasNext()) {
System.out.println("#");
Search search = iterator.next();
search.search("hello world");
}
}
}