SPI相關(guān)源碼分析
- ClassLoader
//F7單步執(zhí)行不會進入,必須使用alt+shift+F7強制進入
//AppClassLoader
loader.getResources(fullName);
//ExtClassLoader、AppClassLoader都繼承UrlClassLoader再繼承ClassLoader,UrlClassLoader中包含UrlClassPath ucp字段,
//返回一個枚舉器(懶惰加載),遍歷枚舉器時才會
Enumeration<Resource> e = UrlClassPath.getResources(String className)
//根據(jù)className遍歷loaders進行加載
e.hasMoreElement()或e.next()
public Enumeration<URL> getResources(String name) throws IOException {
Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];
if (parent != null) {
// AppClassLoader的parent為ExtClassLoader,獲取其組合的枚舉器
tmp[0] = parent.getResources(name);
} else {
// ExtClassLoader的parent為null,組合BootstrapResources
tmp[0] = getBootstrapResources(name);
}
tmp[1] = findResources(name);
return new CompoundEnumeration<>(tmp);
}
- CompoundEnumeration
private boolean next() {
//遍歷枚舉器數(shù)組找到滿足情況的枚舉
while(this.index < this.enums.length) {
if (this.enums[this.index] != null && this.enums[this.index].hasMoreElements()) {
return true;
}
++this.index;
}
return false;
}
- UrlClassPath
public Enumeration<Resource> getResources(final String var1, final boolean var2) {
return new Enumeration<Resource>() {
private int index = 0;
private int[] cache = URLClassPath.this.getLookupCache(var1);
private Resource res = null;
private boolean next() {
if (this.res != null) {
return true;
} else {
do {
URLClassPath.Loader var1x;
// UrlClassPath中包含ArrayList<URLClassPath.Loader> loaders字段,每個loader一般情況下是一個jarLoader,負責(zé)加載jar文件
if ((var1x = URLClassPath.this.getNextLoader(this.cache, this.index++)) == null) {
return false;
}
// 遍歷jarLoader,確定其是否找到對應(yīng)的class
this.res = var1x.getResource(var1, var2);
} while(this.res == null);
return true;
}
}
- ServiceLoader
// ServiceLoader.LazyIterator
// 判斷迭代器中是否還有下一個服務(wù)
private boolean hasNextService() {
if (nextName != null) {
return true;
}
if (configs == null) {
// 組裝META-INF\services\className
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
// 使用AppClassLoader生成枚舉器
configs = loader.getResources(fullName);
}
while ((pending == null) || !pending.hasNext()) {
//第一次進入或當(dāng)?shù)谝粋€META-INF\services\className的file中的所有實現(xiàn)類已經(jīng)初始化完成后,繼續(xù)找其他的實現(xiàn)類file
if (!configs.hasMoreElements()) {
return false;
}
// 解析找到的包含了META-INF\services\className的file的URL,得到實現(xiàn)類名稱的迭代器
pending = parse(service, configs.nextElement());
}
// 返回實現(xiàn)類名稱
nextName = pending.next();
return true;
}
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
// 設(shè)置為null,便于下一次hashNextService時得到下一個實現(xiàn)類的名稱
nextName = null;
Class<?> c = null;
// 找到實現(xiàn)類Class
//第二個參數(shù)表示是否執(zhí)行該class的初始化,初始化的概念如下
https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4
Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.
Initialization of an interface consists of executing the initializers for fields (constants) declared in the interface.
c = Class.forName(cn, false, loader);
S p = service.cast(c.newInstance());
//放入providers數(shù)組中
providers.put(cn, p);
return p;
}
- DriverManager實踐
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
private static void loadInitialDrivers() {
//
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
//找到下一個實現(xiàn)類
while(driversIterator.hasNext()) {
//初始化下一個實現(xiàn)類并放入ServiceLoader.providers中
driversIterator.next();
}
//第一次遍歷迭代器從lazyIterator中獲取對象并設(shè)置到providers中,再次初始化迭代器直接從providers中獲取對應(yīng)的實現(xiàn)類
//driversIterator = loadedDrivers.iterator();
}
//早期的jdbc使用方式
//注冊 JDBC 驅(qū)動
Class.forName(JDBC_DRIVER);
//不確定是如何使用注冊的Driver的
conn = DriverManager.getConnection(DB_URL,USER,PASS);
//后續(xù)的方式
//com.mysql.jdbc.Driver&org.postgresql.Driver都包含如下內(nèi)容
static {
//注冊自己的Driver到DriverManager.registeredDrivers(static)中
//由ServiceLoader中S p = service.cast(c.newInstance()),c為Driver對應(yīng)的Class,觸發(fā)行為
DriverManager.registerDriver(new Driver());
}
//DriverManager.getConnection()
//
for(DriverInfo aDriver : registeredDrivers) {
//測試使用postgrel的Driver去連mysql,此處返回null
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
}
- 不足
接口所有的實現(xiàn)類都newInstance()
ServiceLoader對多線程不夠友好