public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader){
return new ServiceLoader<>(service, loader);
}
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
ServiceLoader的构造方法是私有的所以提供了,两个静态的load方法获取ServiceLoader实例。
public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = Objects.requireNonNull(svc, "Service interface cannot be null");
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
可以看出构造方法什么也没有做,只是初始化了一些实例字段,其中providers是用来缓存所有已经找到的service类的实例。lookupIterator是用来寻找Service实现类的。我们可以看出是一个LazyIteraror.至于为什么是lazy的请看下面代码。
private boolean hasNextService() {
if (nextName != null) {
return true;
}
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
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;
}
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
我们知道ClassLoader的getResources是获取的一个可遍历的对象,但是只有在pending没有next元素之后才回去获取下一个service file文件中的配置的service实现类。所以在遍历实现类的过程中不是一开始就打开所有的service的spi的文件获取所有的实现类的名字,而是只有当某一个文件中的配置类消耗完之后才回去下一个文件之中去寻找,这就是这个lazy的含义。
下面我们看看providers是怎么起到缓存作用的,以及为什么要设置这样的一个缓存。
public final class ServiceLoader<S> implements Iterable<S>
可以看出ServiceLoader是一个Iterable 。他需要实现一个iterator方法去返回Iterator对象
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();
}
};
}
在我们每次使用forEach增强循环或者直接使用Iteraor的时候都会返回一个新的iterator此时如果重新去classpath中去找service的spi文件,加载着些spi文件里面的配置类完全是低效的,所以使用了一个providers去缓存所有的已经加载的service实现类,在每次返回iterator的时候,只需要直接返回着些类就可以了,不需要再次使用LazyIterato去寻找了
|