SPI发现机制
Springmvc的无web.xml启动方式也是用的SPI自动发现机制处理的,都是通过在配置文件中加入实现类全限定名。
标准接口:
package spi;
public interface Fruit {
void name();
}
插拔式实现类1:
package spi;
public class Apple implements Fruit {
@Override
public void name() {
System.out.println("apple");
}
}
插拔式实现类2:
package spi;
public class Orange implements Fruit {
@Override
public void name() {
System.out.println("orange");
}
}
程序调用方式:
package spi;
import java.util.Iterator;
import java.util.ServiceLoader;
public class SPIMain {
public static void main(String[] args) {
ServiceLoader<Fruit> fruits = ServiceLoader.load(Fruit.class);
Iterator<Fruit> iterator = fruits.iterator();
while (iterator.hasNext()) {
Fruit fruit = iterator.next();
fruit.name();
}
}
}
具体读取的配置文件:
META-INF/services/spi.Fruit
spi.Apple
spi.Orange
META-INF/services/是默认前缀,spi.Fruit是需要拓展的标准接口全限定名,内容为具体的实现类全限定名。SPI的实现类必须携带一个不带参数的构造方法。
ServiceLoader类分析:
//实现Iterable接口提供迭代器
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;
// The access control context taken when the ServiceLoader is created
private final AccessControlContext acc;
//提供缓存机制,避免实现类对象重复创建
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
// 懒加载式的迭代器,主要由它创建
private LazyIterator lookupIterator;
......
//主要内部类
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;
}
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;
}
//返回解析出实现类全限定名的迭代器,先判断属性providers是否包含这个类
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
//初始化配置的实现类,false表示不执行类加载过程中的初始化阶段
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 {
//反射生成实现类对象,需要有一个无参构造函数,并且转换为service类型
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 boolean hasNext() {
if (acc == null) {
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
public Boolean run() { return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
public S next() {
if (acc == null) {
return nextService();
} else {
PrivilegedAction<S> action = new PrivilegedAction<S>() {
public S run() { return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
//解析配置实现类的关键方法
private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
List<String> names)
throws IOException, ServiceConfigurationError
{
String ln = r.readLine();
if (ln == null) {
return -1;
}
int ci = ln.indexOf('#');
if (ci >= 0) ln = ln.substring(0, ci);
ln = ln.trim();
int n = ln.length();
if (n != 0) {
if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
fail(service, u, lc, "Illegal configuration-file syntax");
int cp = ln.codePointAt(0);
if (!Character.isJavaIdentifierStart(cp))
fail(service, u, lc, "Illegal provider-class name: " + ln);
for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
cp = ln.codePointAt(i);
if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
fail(service, u, lc, "Illegal provider-class name: " + ln);
}
缓存中不存在此类且遍历集合中不包含,则加入集合
if (!providers.containsKey(ln) && !names.contains(ln))
names.add(ln);
}
return lc + 1;
}
}
来源:CSDN
作者:qq_36744284
链接:https://blog.csdn.net/qq_36744284/article/details/103647382