首先看strategies 屬性的定義:
private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();
點(diǎn)進(jìn)去看初始化方法:loadLoadingStrategies()
private static LoadingStrategy[] loadLoadingStrategies() {
return java.util.stream.StreamSupport.stream(java.util.ServiceLoader.load(LoadingStrategy.class).spliterator(), false)
.sorted()
.toArray(LoadingStrategy[]::new);
}
加載過程解析
ServiceLoader.load方法迎罗,利用的是jdk自帶的spi機(jī)制睬愤,加載 LoadingStrategy類的實(shí)現(xiàn)類,
jdk的spi機(jī)制約定了纹安,接口實(shí)現(xiàn)類的描述文件存放位置為:META-INFO/services/尤辱,文件名稱為接口的全限定名,即 org.apache.dubbo.common.extension.LoadingStrategy
厢岂,文件內(nèi)容如下:
org.apache.dubbo.common.extension.DubboInternalLoadingStrategy
org.apache.dubbo.common.extension.DubboLoadingStrategy
org.apache.dubbo.common.extension.ServicesLoadingStrategy
顯然光督,LoadingStrategy接口有三種實(shí)現(xiàn),因此塔粒,jdk的spi機(jī)制结借,會將這三個實(shí)現(xiàn)分別初始化,并以數(shù)組的方式填充到 strategies
屬性中卒茬,也就是說船老,不同的屬性代表著不同的加載策略。
到這一步圃酵,strategies
屬性就加載完成了柳畔。那么,strategies
字段在哪里使用呢辜昵?
我們再來看這一段代碼:
private Map<String, Class<?>> loadExtensionClasses() {
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
for (LoadingStrategy strategy : strategies) {
loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
}
return extensionClasses;
}
總結(jié):strategies中的每一項(xiàng)荸镊,代表著不同的spi加載策略,每一種加載策略堪置,都有相應(yīng)的目錄結(jié)構(gòu)躬存。因此dubbo通過遍歷strategies,來讀取某一個接口在所有策略下的所有實(shí)現(xiàn)類舀锨,并以k - v的方式緩存到extensionClasses
中岭洲,但是到這一步,還僅僅讀取了實(shí)現(xiàn)類的class對象坎匿,而沒有進(jìn)行初始化盾剩。后續(xù)使用實(shí)現(xiàn)類時雷激,可以直接拿到class對象,而不需要再去讀取文件了告私。