定义接口
public interface IFunctionService {
void test();
}
定义接口实现,这里实现了三个实现类。
public class FunctionService1 implements IFunctionService {
private static final String TAG = "FunctionService1";
@Override
public void test() {
Log.e(TAG, "test1: ");
}
}
public class FunctionService2 implements IFunctionService {
private static final String TAG = "FunctionService2";
@Override
public void test() {
Log.e(TAG, "test2: " );
}
}
public class FunctionService3 implements IFunctionService {
private static final String TAG = "StrategyService3";
@Override
public void test() {
Log.e(TAG, "test3: " );
}
}
编写配置文件,在src/main文件下创建resources/META-INF/services文件夹,然后在其中创建文件,文件名字是接口的全限定类名,内容是实现类的全限定类名,多个实现类用换行符分隔,如下:com.example.testspi.IFunctionService
注意:META-INF/services/文件路径不可以改变,这个在代码中写死的。

文件的内容如下:
com.example.testspi.FunctionService1
com.example.testspi.FunctionService2
com.example.testspi.FunctionService3
public static void main(String[] args) {
ServiceLoader<IFunctionService> load = ServiceLoader.load(IFunctionService.class);
for (IFunctionService iFunctionService : load) {
iFunctionService.test();
}
}
服务提供者接口(Service Provider Interface,简写为SPI)是JDK内置的一种服务提供发现机制。可以用来加载框架扩展和替换组件,主要是被框架的开发人员使用。在java.util.ServiceLoader的文档里有比较详细的介绍。
Java中SPI机制主要思想是将装配的控制权移到程序之外,是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制,有点类似Spring的IOC机制。在模块化设计中这个机制尤其重要,其核心思想就是解耦。
当服务的提供者,提供了服务接口的某种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。基于这样一个约定就能实现服务接口与实现的解耦。
不能按需加载,需要遍历所有的实现,并实例化,然后在循环中才能找到我们需要的实现。如果不想用某些实现类,或者某些类实例化很耗时,它也被载入并实例化了,这就造成了浪费。
多个并发多线程使用ServiceLoader类的实例是不安全的。
扩展如果依赖其他的扩展,做不到自动注入和装配。
今天按照方法的调用过程对源码进行分析。
public final class ServiceLoader<S> implements Iterable<S> {
//接口配置文件对应的路径。
private static final String PREFIX = "META-INF/services/";
// 表示正在加载的服务的类或接口
private final Class<S> service;
// 用于定位、加载和实例化提供程序的类加载器
private final ClassLoader loader;
//创建ServiceLoader时采用的访问控制上下文
private LinkedHashMap<String, S> providers = new LinkedHashMap<>();
// 懒加载迭代器
private LazyIterator lookupIterator;
................
}
load()
为给定的服务类型创建一个新的服务加载器。
public static <S> ServiceLoader<S> load(Class<S> service) {
//获取类加载器
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
调用重载方法load
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader) {
return new ServiceLoader<>(service, loader);
}
创建ClassLoader对象
private ServiceLoader(Class<S> svc, ClassLoader cl) {
//其实就是svc
service = Objects.requireNonNull(svc, "Service interface cannot be null");
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
reload();
}
调用reload
清除此加载器的实现类对象缓存,以便重新加载所有实现类对象。
public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
LayIterator创建
LazyIterator是一个迭代器,查找实现类和创建实现类的过程,都在LazyIterator完成。
private class LazyIterator implements Iterator<S> {
Class<S> service;
ClassLoader loader;
Enumeration<URL> configs = null;
Iterator<String> pending = null;
String nextName = null;
private LazyIterator(Class<S> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}
迭代
当我们调用iterator.hasNext和iterator.next方法的时候,实际上调用的都是LazyIterator的相应方法。
public Iterator<S> iterator() {
return new Iterator<S>() {
Iterator<Map.Entry<String, S>> knownProviders
= providers.entrySet().iterator();
public boolean hasNext() {
if (knownProviders.hasNext())
return true;
return lookupIterator.hasNext();
}
public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
return lookupIterator.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
hasNextService
private boolean hasNextService() {
//第二次调用的时候,已经解析完成了,直接返回
if (nextName != null) {
return true;
}
//如果读取过则不在重新读取
if (configs == null) {
try {
//配置文件路径,加上接口的全限定类名,就是文件服务类的文件
String fullName = PREFIX + service.getName();
//从路径中读取配置,将文件路径转成URL对象
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
//解析URL文件对象,读取内容,最后返回
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
nextService
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
//读取类对象
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
// Android-changed: Let the ServiceConfigurationError have a cause.
"Provider " + cn + " not found", x);
// "Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
// Android-changed: Let the ServiceConfigurationError have a cause.
ClassCastException cce = new ClassCastException(
service.getCanonicalName() + " is not assignable from " + c.getCanonicalName());
fail(service,
"Provider " + cn + " not a subtype", cce);
// fail(service,
// "Provider " + cn + " not a subtype");
}
try {
//强转。
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service,
"Provider " + cn + " could not be instantiated",
x);
}
throw new Error(); // This cannot happen
}