1.什麼是SPI
SPI全稱Service Provide Interface,是JDK內置的一種服務提供發現機制(如:JDBC)。是一種動態替換髮現機制。例如:有個接口想在運行時才發現具體的實現類,那麼你只需要在程序運行前添加一個實現即可,並把新加的實現描述給JDK即可。實現類系統類加載器AppClassLoader來加載(注:這裏是違反了類加載器雙親委派模式)。
2.SPI規範
3.SPI使用
1.定義接口
2.設置實現類
3.設置類加載配置文件
4.使用
添加依賴
類加載
5.SPI缺點
我們使用SPI查找具體的實現的時候,需要遍歷所有的實現,並實例化,然後我們在循環中才能找到我們需要實現。這應該也是最大的缺點,需要把所有的實現都實例化了,即便我們不需要,也都給實例化了。
結果
5.ServiceLoader源碼簡單分析
1.獲取上下文類加載器(App ClassLoader)
/**
*
*獲取上下文類加載器
*/
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
2.初始化服務提供者查找的迭代器
public void reload() {
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
3.服務提供者查找的迭代器
private class LazyIterator
implements Iterator<S>
{
//服務提供者接口 例如:Hello
Class<S> service;
//類加載器
ClassLoader loader;
//保存實現類的url
Enumeration<URL> configs = null;
//保存實現類的名稱
Iterator<String> pending = null;
//下一個實現類的名稱
String nextName = null;
private LazyIterator(Class<S> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}
}
4.實現迭代器的方法 在迭代的時候纔會去獲取具體實現接口的實例
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;
}
//獲取服務
private S nextService() {
if (!hasNextService())
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,
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);
}
}