在上一篇文章:Java SPI(Service Provider Interface)简介 中对Java SPI机制做了简单说明,并附上了一个具体的demo。对Java SPI不熟悉的同学可以去参阅一下那篇文章,本文不再赘述。
本文将在上一篇文章的基础之上,结合JDK 1.7 源码来剖析Java SPI的内部实现原理。
在上一篇文章中,我们通过如下代码获取Service的具体实现,代码如下:
import java.util.Iterator;
import java.util.ServiceLoader;
import com.ricky.codelab.spi.DemoService;
//1.ServiceLoader.load
ServiceLoader<DemoService> serviceLoader = ServiceLoader.load(DemoService.class);
//2.serviceLoader.iterator()
Iterator<DemoService> it = serviceLoader.iterator();
//3.hasNext()
while (it.hasNext()) {
//4.next()
DemoService demoService = it.next();
}
1、ServiceLoader.load方法
首先来看看ServiceLoader.load方法,如下:
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
它有一个重载方法,如下:
public static <S> ServiceLoader<S> load(Class<S> service,
ClassLoader loader){
return new ServiceLoader<>(service, loader);
}
这里通过调用 new ServiceLoader<>(service, loader)返回一个ServiceLoader实例对象,ServiceLoader<>(service, loader)构造方法如下:
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = svc;
loader = cl;
reload();
}
构造方法内部调用了reload方法,如下:
public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
providers、lookupIterator 属性定义如下:
// The class loader used to locate, load, and instantiate providers
private ClassLoader loader;
// Cached providers, in instantiation order
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
// The current lazy-lookup iterator
private LazyIterator lookupIterator;
接下来看看ServiceLoader内部类LazyIterator的实现代码,如下:
// Private inner class implementing fully-lazy provider lookup
//
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;
}
public boolean hasNext() {
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;
}
public S next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
"Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
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
}
public void remove() {
throw new UnsupportedOperationException();
}
}
其中,PREFIX 定义如下:
private static final String PREFIX = "META-INF/services/";
2、ServiceLoader iterator方法
当执行 Iterator it = serviceLoader.iterator(); 代码时,执行的是ServiceLoader 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();
}
};
}
返回了一个Iterator的匿名类,
Iterator hasNext()方法
while (it.hasNext()) {
DemoService demoService = it.next();
}
it.hasNext()调用的是上述返回的 new Iterator()的public boolean hasNext()方法。
Iterator next方法
it.next();调用的是上述返回的 new Iterator()的public S next() 方法。