ServiceLoader整理
ServiceLoader简单使用
Search search = null; ServiceLoader<Search> serviceLoader = ServiceLoader.load(Search.class); Iterator<Search> searchs = serviceLoader.iterator(); if (searchs.hasNext()) { search = searchs.next(); }
-
源码分析
- 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);
}
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = svc;
loader = cl;
reload();
}
public void reload() {
providers.clear();//private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
lookupIterator = new LazyIterator(service, loader);
}
private class LazyIterator implements Iterator<S>//这里叫lazy其实就是调用hasNext的时候才去加载
{
...
private LazyIterator(Class<S> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}
...
}
- public static <S> ServiceLoader<S> load(Class<S> service) {
- iterator()
-
}public Iterator<S> iterator() { return new Iterator<S>() {//返回匿名内部类 Iterator<Map.Entry<String,S>> knownProviders = providers.entrySet().iterator();//目前这个linkedhashmap还是空的 public boolean hasNext() { if (knownProviders.hasNext()) return true; return lookupIterator.hasNext();//knownProviders空时走这个 } public S next() { if (knownProviders.hasNext()) return knownProviders.next().getValue(); return lookupIterator.next(); } public void remove() { throw new UnsupportedOperationException(); } };
-
- hasNext()
- public boolean hasNext() {
if (nextName != null) {//null 调用next后会置nextName为null,不调用next则nextName始终不为null
return true;
}
if (configs == null) {//null
try {
String fullName = PREFIX + service.getName();
if (loader == null)//null
configs = ClassLoader.getSystemResources(fullName);
else
//这里加载资源: META-INF/services/packageName.className
//Finds all the resources with the given name.
//A resource is some data (images, audio, text, etc) that can be accessed by class code in a way that is independent of the location of the code.
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
while ((pending == null) || !pending.hasNext()) {//null
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());//go here
}
nextName = pending.next();// Iterator<String> pending
return true;
} - private Iterator<String> parse(Class service, URL u)throws ServiceConfigurationError
{
InputStream in = null;
BufferedReader r = null;
ArrayList<String> names = new ArrayList<>();
try {
in = u.openStream();
r = new BufferedReader(new InputStreamReader(in, "utf-8"));
int lc = 1;
while ((lc = parseLine(service, u, r, lc, names)) >= 0);
} catch (IOException x) {
fail(service, "Error reading configuration file", x);
} finally {
try {
if (r != null) r.close();
if (in != null) in.close();
} catch (IOException y) {
fail(service, "Error closing configuration file", y);
}
}
return names.iterator();
}
- public boolean hasNext() {
- next()
- public S next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
String cn = nextName;
nextName = null;// *** 置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());// Casts an object to the class or interface represented by this Class object
providers.put(cn, p);// add cache 放入到knownProviders里面
return p;
} catch (Throwable x) {
fail(service, "Provider " + cn + " could not be instantiated: " + x, x);
}
throw new Error();// This cannot happen
}
- public S next() {
-
小结
- hasNext和next必须搭配一起使用
- hasNext获取nextName从一个Iterator<String>的pending中
- next则拿这个nextName去加载创建Class并创建对象返回
- 首次从lookupIterator中获取,后面从knownProviders缓存里面获取
- hasNext和next必须搭配一起使用
- ServiceLoader.load
-
References