ServiceLoader
JDK 实现的 service 装载。
A service provider is a specific implementation of a service
实例:JDBC 驱动
How to use
配置文件
- provider-configuration file in the resource directory META-INF/services.
- 注释使用
#
- 必须
UTF-8
- 配置文件和代码可以放于不同的jar
- 懒加载&懒获取
Example
我们有 抽象类com.example.CodecSet
public abstract class CodecSet {
public abstract Encoder getEncoder(String encodingName);
public abstract Decoder getDecoder(String encodingName);
}
我们还有实现com.example.impl.StandardCodecs
public class StandardCodecs extends CodecSet {
@Override
public Encoder getEncoder(String encodingName) {
return null;
}
@Override
public Decoder getDecoder(String encodingName) {
return null;
}
}
实现类注册文件
META-INF/services/com.example.CodecSet This file contains the single line:
com.example.impl.StandardCodecs
获取实例:
ServiceLoader<CodecSet> codecSetLoader = ServiceLoader.load(CodecSet.class);
CodecSet codecSet = null;
for (CodecSet cp : codecSetLoader) {
codecSet = cp;
break;
}
System.out.println(codecSet.getClass().toString());
输出
class com.example.impl.StandardCodecs
fun point
ServiceLoader.LazyIterator
懒加载 ServiceLoader
实习了 Iterable
接口,内部实际执行委托给LazyIterator
关键流程
hasNextService
- 加载相关文件
Class<S> service;
ClassLoader loader;
Enumeration<URL> 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());
}
next
加载类
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
"Provider " + cn + " not found");
}
放入缓存
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
缓存机制
reload 方法
// Cached providers, in instantiation order
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
迭代器
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();
}
};
基本原理
knownProviders
在创建时,内容是个快照.