前面我們了解過(guò)了Java的SPI擴(kuò)展機(jī)制莲绰,對(duì)于Java擴(kuò)展機(jī)制的原理以及優(yōu)缺點(diǎn)也有了大概的了解枯夜,這里繼續(xù)深入一下Dubbo的擴(kuò)展點(diǎn)加載機(jī)制。
Dubbo擴(kuò)展點(diǎn)加載的功能
Dubbo的擴(kuò)展點(diǎn)加載機(jī)制類(lèi)似于Java的SPI矾瑰,我們知道Java的SPI在使用的時(shí)候倦蚪,只能通過(guò)遍歷來(lái)進(jìn)行實(shí)現(xiàn)的查找和實(shí)例化,有可能會(huì)一次性把所有的實(shí)現(xiàn)都實(shí)例化痢法,這樣會(huì)造成有些不使用的擴(kuò)展實(shí)現(xiàn)也會(huì)被實(shí)例化狱窘,這就會(huì)造成一定的資源浪費(fèi)。有關(guān)Dubbo的改進(jìn)财搁,參照文檔上的說(shuō)明:
- JDK標(biāo)準(zhǔn)的SPI會(huì)一次性實(shí)例化擴(kuò)展點(diǎn)所有實(shí)現(xiàn)蘸炸,如果有擴(kuò)展實(shí)現(xiàn)初始化很耗時(shí),但如果沒(méi)用上也加載妇拯,會(huì)很浪費(fèi)資源幻馁。
- 如果擴(kuò)展點(diǎn)加載失敗,連擴(kuò)展點(diǎn)的名稱(chēng)都拿不到了越锈。比如:JDK標(biāo)準(zhǔn)的ScriptEngine仗嗦,通過(guò)getName();獲取腳本類(lèi)型的名稱(chēng),但如果RubyScriptEngine因?yàn)樗蕾嚨膉ruby.jar不存在甘凭,導(dǎo)致RubyScriptEngine類(lèi)加載失敗稀拐,這個(gè)失敗原因被吃掉了,和ruby對(duì)應(yīng)不起來(lái)丹弱,當(dāng)用戶執(zhí)行ruby腳本時(shí)德撬,會(huì)報(bào)不支持ruby铲咨,而不是真正失敗的原因。
- 增加了對(duì)擴(kuò)展點(diǎn)IoC和AOP的支持蜓洪,一個(gè)擴(kuò)展點(diǎn)可以直接setter注入其它擴(kuò)展點(diǎn)纤勒。
關(guān)于第一點(diǎn),通過(guò)和Java的SPI對(duì)比隆檀,就能明白摇天;第二點(diǎn)還未做測(cè)試,不太清楚其中的緣由恐仑;第三點(diǎn)對(duì)于IOC和AOP的支持下面簡(jiǎn)單介紹下泉坐。
擴(kuò)展點(diǎn)自動(dòng)裝配功能(IOC)
就是當(dāng)加載一個(gè)擴(kuò)展點(diǎn)時(shí),會(huì)自動(dòng)的注入這個(gè)擴(kuò)展點(diǎn)所依賴的其他擴(kuò)展點(diǎn)裳仆,如果描述不清楚的話腕让,可以看下下面的例子:
接口A,實(shí)現(xiàn)類(lèi)A1歧斟,A2
接口B纯丸,實(shí)現(xiàn)類(lèi)B1,B2
其中實(shí)現(xiàn)類(lèi)A1含有setB()方法构捡,當(dāng)通過(guò)擴(kuò)展機(jī)制加載A的實(shí)現(xiàn)的時(shí)候液南,會(huì)自動(dòng)的注入一個(gè)B的實(shí)現(xiàn)類(lèi),但是勾徽,此時(shí)不是注入B1,也不是注入B2统扳,而是注入一個(gè)自適應(yīng)的B的實(shí)現(xiàn)類(lèi):B$Adpative
喘帚,該實(shí)現(xiàn)類(lèi)是動(dòng)態(tài)生成的,能夠根據(jù)參數(shù)的不同咒钟,自動(dòng)選擇B1或者B2來(lái)進(jìn)行調(diào)用吹由。
擴(kuò)展點(diǎn)自適應(yīng)
上面我們說(shuō),在自動(dòng)裝配的時(shí)候朱嘴,并不是注入一個(gè)真正的實(shí)現(xiàn)倾鲫,而是注入一個(gè)自適應(yīng)的擴(kuò)展點(diǎn)實(shí)現(xiàn),其實(shí)就是動(dòng)態(tài)的生成的代碼萍嬉,也就是手動(dòng)拼裝的代碼乌昔,這段代碼里會(huì)根據(jù)SPI上配置的信息來(lái)加入對(duì)于具體實(shí)現(xiàn)的選擇功能。生成的代碼類(lèi)似于下面的壤追,代碼做了一下精簡(jiǎn)磕道,把包都去掉了:
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements Protocol {
public Invoker refer(Class arg0, URL arg1) throws Class {
if (arg1 == null) throw new IllegalArgumentException("url == null");
URL url = arg1;
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(Protocol) name from url(" + url.toString() + ") use keys([protocol])");
Protocol extension = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
public Exporter export(Invoker arg0) throws Invoker {
if (arg0 == null) throw new IllegalArgumentException("Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("Invoker argument getUrl() == null");URL url = arg0.getUrl();
//這里會(huì)根據(jù)url中的信息獲取具體的實(shí)現(xiàn)類(lèi)名
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(Protocol) name from url(" + url.toString() + ") use keys([protocol])");
//根據(jù)上面的實(shí)現(xiàn)類(lèi)名,會(huì)在運(yùn)行時(shí)行冰,通過(guò)Dubbo的擴(kuò)展機(jī)制加載具體實(shí)現(xiàn)類(lèi)
Protocol extension = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);
return extension.export(arg0);
}
public void destroy() {
throw new UnsupportedOperationException("method public abstract void Protocol.destroy() of interface Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("method public abstract int Protocol.getDefaultPort() of interface Protocol is not adaptive method!");
}
}
使用這種方式的原因也很容易能想到溺蕉,在我們加載擴(kuò)展點(diǎn)實(shí)現(xiàn)的時(shí)候伶丐,并沒(méi)有調(diào)用實(shí)現(xiàn)的具體邏輯,那我們注入一個(gè)擴(kuò)展點(diǎn)疯特,也就不知道這個(gè)擴(kuò)展點(diǎn)的實(shí)現(xiàn)具體是什么哗魂,所以要注入一個(gè)自適應(yīng)的實(shí)現(xiàn)。等到運(yùn)行時(shí)候漓雅,才根據(jù)自適應(yīng)實(shí)現(xiàn)啡彬,來(lái)調(diào)用真正實(shí)現(xiàn)。
擴(kuò)展點(diǎn)自動(dòng)包裝功能(AOP)
先看下下面的示例故硅,假如接口A還有另外一個(gè)實(shí)現(xiàn)者:AWrapper1:
class AWrapper1 implements A{
private A a;
AWrapper1(A a){
this.a = a;
}
}
AWrapper1相當(dāng)于A的包裝類(lèi)庶灿,類(lèi)似于AOP的功能,AWrapper1增加了A的功能吃衅。當(dāng)我們獲取接口A的實(shí)現(xiàn)類(lèi)的時(shí)候往踢,得到的就是包裝過(guò)的類(lèi)。
Dubbo擴(kuò)展點(diǎn)加載的實(shí)現(xiàn)
首先還是定義接口徘层,然后是接口的具體實(shí)現(xiàn)類(lèi)峻呕,配置文件類(lèi)似于Java的SPI配置文件,Dubbo的配置文件放在META-INF/dubbo/
目錄下趣效,配置文件名為接口的全限定名瘦癌,配置文件內(nèi)容是配置名=擴(kuò)展實(shí)現(xiàn)類(lèi)的全限定名
,加載實(shí)現(xiàn)類(lèi)的功能是通過(guò)ExtensionLoader來(lái)實(shí)現(xiàn)跷敬,類(lèi)似于Java中的ServiceLoader的作用讯私。
另外,擴(kuò)展點(diǎn)使用單一實(shí)例加載西傀,需要確保線程安全性斤寇。
Dubbo擴(kuò)展點(diǎn)加載的一些定義
@SPI
注解,被此注解標(biāo)記的接口拥褂,就表示是一個(gè)可擴(kuò)展的接口娘锁。-
@Adaptive
注解,有兩種注解方式:一種是注解在類(lèi)上饺鹃,一種是注解在方法上莫秆。- 注解在類(lèi)上,而且是注解在實(shí)現(xiàn)類(lèi)上悔详,目前dubbo只有AdaptiveCompiler和AdaptiveExtensionFactory類(lèi)上標(biāo)注了此注解镊屎,這是些特殊的類(lèi),ExtensionLoader需要依賴他們工作伟端,所以得使用此方式杯道。
- 注解在方法上,注解在接口的方法上,除了上面兩個(gè)類(lèi)之外党巾,所有的都是注解在方法上萎庭。ExtensionLoader根據(jù)接口定義動(dòng)態(tài)的生成適配器代碼,并實(shí)例化這個(gè)生成的動(dòng)態(tài)類(lèi)齿拂。被Adaptive注解的方法會(huì)生成具體的方法實(shí)現(xiàn)驳规。沒(méi)有注解的方法生成的實(shí)現(xiàn)都是拋不支持的操作異常UnsupportedOperationException。被注解的方法在生成的動(dòng)態(tài)類(lèi)中署海,會(huì)根據(jù)url里的參數(shù)信息吗购,來(lái)決定實(shí)際調(diào)用哪個(gè)擴(kuò)展。
比如說(shuō)這段代碼:
private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
當(dāng)上面代碼執(zhí)行的時(shí)候砸狞,我們其實(shí)還不知道要真正使用的Protocol是什么捻勉,可能是具體的實(shí)現(xiàn)DubboProtocol,也可能是其他的具體實(shí)現(xiàn)的Protocol刀森,那么這時(shí)候refprotocol到底是什么呢踱启?refprotocol其實(shí)是在調(diào)用getAdaptiveExtension()方法時(shí)候,自動(dòng)生成的一個(gè)類(lèi)研底,代碼如下:
import com.alibaba.dubbo.common.extension.ExtensionLoader; public class Protocol$Adpative implements Protocol { public Invoker refer(Class arg0, URL arg1) throws Class { if (arg1 == null) throw new IllegalArgumentException("url == null"); URL url = arg1; String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() ); if(extName == null) throw new IllegalStateException("Fail to get extension(Protocol) name from url(" + url.toString() + ") use keys([protocol])"); Protocol extension = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName); return extension.refer(arg0, arg1); } public Exporter export(Invoker arg0) throws Invoker { if (arg0 == null) throw new IllegalArgumentException("Invoker argument == null"); if (arg0.getUrl() == null) throw new IllegalArgumentException("Invoker argument getUrl() == null");URL url = arg0.getUrl(); String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() ); if(extName == null) throw new IllegalStateException("Fail to get extension(Protocol) name from url(" + url.toString() + ") use keys([protocol])"); Protocol extension = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName); return extension.export(arg0); } public void destroy() { throw new UnsupportedOperationException("method public abstract void Protocol.destroy() of interface Protocol is not adaptive method!"); } public int getDefaultPort() { throw new UnsupportedOperationException("method public abstract int Protocol.getDefaultPort() of interface Protocol is not adaptive method!"); } }
可以看到被@Adaptive注解的方法都生成了具體的實(shí)現(xiàn)埠偿,并且實(shí)現(xiàn)邏輯都相同。而沒(méi)有被注解的方法直接拋出不支持操作的異常榜晦。
當(dāng)我們使用refprotocol調(diào)用方法的時(shí)候冠蒋,其實(shí)是調(diào)用生成的類(lèi)
Protocol$Adpative
中的方法,這里面的方法根據(jù)url中的參數(shù)配置來(lái)找到具體的實(shí)現(xiàn)類(lèi)乾胶,找具體實(shí)現(xiàn)類(lèi)的方式還是通過(guò)dubbo的擴(kuò)展機(jī)制抖剿。比如url中可能會(huì)有protocol=dubbo,此時(shí)就可以根據(jù)這個(gè)dubbo來(lái)確定我們要找的類(lèi)是DubboProtocol胚吁⊙捞桑可以查看下生成的代碼中getExtension(extName)
這里是根據(jù)具體的名字去查找實(shí)現(xiàn)類(lèi)。 @Activate
注解腕扶,此注解需要注解在類(lèi)上或者方法上,并注明被激活的條件吨掌,以及所有的被激活實(shí)現(xiàn)類(lèi)中的排序信息半抱。ExtensionLoader,是dubbo的SPI機(jī)制的查找服務(wù)實(shí)現(xiàn)的工具類(lèi)膜宋,類(lèi)似與Java的ServiceLoader窿侈,可做類(lèi)比。dubbo約定擴(kuò)展點(diǎn)配置文件放在classpath下的
/META-INF/dubbo秋茫,/META-INF/dubbo/internal史简,/META-INF/services
目錄下,配置文件名為接口的全限定名肛著,配置文件內(nèi)容為配置名=擴(kuò)展實(shí)現(xiàn)類(lèi)的全限定名
圆兵。
Dubbo擴(kuò)展點(diǎn)加載的源碼解析
重點(diǎn)解析下ExtensionLoader這個(gè)類(lèi)跺讯。Dubbo的擴(kuò)展點(diǎn)使用單一實(shí)例去加載,緩存在ExtensionLoader中殉农。每一個(gè)ExtensionLoader實(shí)例僅負(fù)責(zé)加載特定SPI擴(kuò)展的實(shí)現(xiàn)刀脏,想要獲得某個(gè)擴(kuò)展的實(shí)現(xiàn),首先要獲得該擴(kuò)展對(duì)應(yīng)的ExtensionLoader實(shí)例超凳。
以Protocol為例進(jìn)行分析擴(kuò)展點(diǎn)的加載:
//這樣使用愈污,先獲取ExtensionLoader實(shí)例,然后加載自適應(yīng)的Protocol擴(kuò)展點(diǎn)
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
//使用
protocol.refer(Class<T> type, URL url))轮傍;
可以看到暂雹,使用擴(kuò)展點(diǎn)加載的步驟大概有三步:
- 獲取ExtensionLoader實(shí)例。
- 獲取自適應(yīng)實(shí)現(xiàn)创夜。
- 使用獲取到的實(shí)現(xiàn)杭跪。
下面我們就以這三步作為分界,來(lái)深入源碼的解析挥下。
獲取ExtensionLoader實(shí)例
第一步揍魂,getExtensionLoader(Protocol.class),根據(jù)要加載的接口Protocol棚瘟,創(chuàng)建出一個(gè)ExtensionLoader實(shí)例现斋,加載完的實(shí)例會(huì)被緩存起來(lái),下次再加載Protocol的ExtensionLoader的時(shí)候偎蘸,會(huì)使用已經(jīng)緩存的這個(gè)庄蹋,不會(huì)再新建一個(gè)實(shí)例:
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
//擴(kuò)展點(diǎn)類(lèi)型不能為空
if (type == null)
throw new IllegalArgumentException();
//擴(kuò)展點(diǎn)類(lèi)型只能是接口類(lèi)型的
if(!type.isInterface()) {
throw new IllegalArgumentException();
}
//沒(méi)有添加@SPI注解,只有注解了@SPI的才會(huì)解析
if(!withExtensionAnnotation(type)) {
throw new IllegalArgumentException();
}
//先從緩存中獲取指定類(lèi)型的ExtensionLoader
//EXTENSION_LOADERS是一個(gè)ConcurrentHashMap迷雪,緩存了所有已經(jīng)加載的ExtensionLoader的實(shí)例
//比如這里加載Protocol.class限书,就以Protocol.class作為key,以新創(chuàng)建的ExtensionLoader作為value
//每一個(gè)要加載的擴(kuò)展點(diǎn)只會(huì)對(duì)應(yīng)一個(gè)ExtensionLoader實(shí)例章咧,也就是只會(huì)存在一個(gè)Protocol.class在緩存中
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
//緩存中不存在
if (loader == null) {
//創(chuàng)建一個(gè)新的ExtensionLoader實(shí)例倦西,放到緩存中去
//對(duì)于每一個(gè)擴(kuò)展,dubbo中只有一個(gè)對(duì)應(yīng)的ExtensionLoader實(shí)例
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
上面代碼返回一個(gè)ExtensionLoader實(shí)例赁严,getExtensionLoader(Protocol.class)
這一步?jīng)]有進(jìn)行任何的加載工作扰柠,只是獲得了一個(gè)ExtensionLoader的實(shí)例。
ExtensionLoader的構(gòu)造方法
上面獲取的是一個(gè)ExtensionLoader實(shí)例疼约,接著看下構(gòu)造實(shí)例的時(shí)候到底做了什么卤档,我們發(fā)現(xiàn)在ExtensionLoader中只有一個(gè)私有的構(gòu)造方法:
private ExtensionLoader(Class<?> type) {
//接口類(lèi)型
this.type = type;
//對(duì)于擴(kuò)展類(lèi)型是ExtensionFactory的,設(shè)置為null
//getAdaptiveExtension方法獲取一個(gè)運(yùn)行時(shí)自適應(yīng)的擴(kuò)展類(lèi)型
//每個(gè)Extension只能有一個(gè)@Adaptive類(lèi)型的實(shí)現(xiàn)程剥,如果么有劝枣,dubbo會(huì)自動(dòng)生成一個(gè)類(lèi)
//objectFactory是一個(gè)ExtensionFactory類(lèi)型的屬性,主要用于加載需要注入的類(lèi)型的實(shí)現(xiàn)
//objectFactory主要用在注入那一步,詳細(xì)說(shuō)明見(jiàn)注入時(shí)候的說(shuō)明
//這里記住非ExtensionFactory類(lèi)型的返回的都是一個(gè)AdaptiveExtensionFactory
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
不難理解舔腾,ExtensionFactory是主要是用來(lái)加載被注入的類(lèi)的實(shí)現(xiàn)溪胶,分為SpiExtensionFactory和SpringExtensionFactory兩個(gè),分別用來(lái)加載SPI擴(kuò)展實(shí)現(xiàn)和Spring中bean的實(shí)現(xiàn)琢唾。
獲取自適應(yīng)實(shí)現(xiàn)
上面返回一個(gè)ExtensionLoader的實(shí)例之后载荔,開(kāi)始加載自適應(yīng)實(shí)現(xiàn),加載是在調(diào)用getAdaptiveExtension()方法中進(jìn)行的:
getAdaptiveExtension()-->
createAdaptiveExtension()-->
getAdaptiveExtensionClass()-->
getExtensionClasses()-->
loadExtensionClasses()
先看下getAdaptiveExtension()方法采桃,用來(lái)獲取一個(gè)擴(kuò)展的自適應(yīng)實(shí)現(xiàn)類(lèi)懒熙,最后返回的自適應(yīng)實(shí)現(xiàn)類(lèi)是一個(gè)類(lèi)名為Protocol$Adaptive
的類(lèi),并且這個(gè)類(lèi)實(shí)現(xiàn)了Protocol接口:
public T getAdaptiveExtension() {
//先從實(shí)例緩存中查找實(shí)例對(duì)象
//private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
//在當(dāng)前的ExtensionLoader中保存著一個(gè)Holder實(shí)例普办,用來(lái)緩存自適應(yīng)實(shí)現(xiàn)類(lèi)的實(shí)例
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {//緩存中不存在
if(createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
//獲取鎖之后再檢查一次緩存中是不是已經(jīng)存在
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//緩存中沒(méi)有工扎,就創(chuàng)建新的AdaptiveExtension實(shí)例
instance = createAdaptiveExtension();
//新實(shí)例加入緩存
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {createAdaptiveInstanceError = t; }
}
}
}
}
return (T) instance;
}
創(chuàng)建自適應(yīng)擴(kuò)展
緩存中不存在自適應(yīng)擴(kuò)展的實(shí)例,表示還沒(méi)有創(chuàng)建過(guò)自適應(yīng)擴(kuò)展的實(shí)例衔蹲,接下來(lái)就是創(chuàng)建自適應(yīng)擴(kuò)展實(shí)現(xiàn)肢娘,createAdaptiveExtension()方法,用來(lái)創(chuàng)建自適應(yīng)擴(kuò)展類(lèi)的實(shí)例:
private T createAdaptiveExtension() {
try {
//先通過(guò)getAdaptiveExtensionClass獲取AdaptiveExtensionClass
//然后獲取其實(shí)例
//最后進(jìn)行注入處理
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {}
}
獲取自適應(yīng)擴(kuò)展類(lèi)
接著查看getAdaptiveExtensionClass()方法舆驶,用來(lái)獲取一個(gè)自適應(yīng)擴(kuò)展的Class橱健,這個(gè)Class將會(huì)在下一步被實(shí)例化:
private Class<?> getAdaptiveExtensionClass() {
//加載當(dāng)前Extension的所有實(shí)現(xiàn)(這里舉例是Protocol,只會(huì)加載Protocol的所有實(shí)現(xiàn)類(lèi))沙廉,如果有@Adaptive類(lèi)型的實(shí)現(xiàn)類(lèi)拘荡,會(huì)賦值給cachedAdaptiveClass
//目前只有AdaptiveExtensionFactory和AdaptiveCompiler兩個(gè)實(shí)現(xiàn)類(lèi)是被注解了@Adaptive
//除了ExtensionFactory和Compiler類(lèi)型的擴(kuò)展之外,其他類(lèi)型的擴(kuò)展都是下面動(dòng)態(tài)創(chuàng)建的的實(shí)現(xiàn)
getExtensionClasses();
//加載完所有的實(shí)現(xiàn)之后撬陵,發(fā)現(xiàn)有cachedAdaptiveClass不為空
//也就是說(shuō)當(dāng)前獲取的自適應(yīng)實(shí)現(xiàn)類(lèi)是AdaptiveExtensionFactory或者是AdaptiveCompiler珊皿,就直接返回,這兩個(gè)類(lèi)是特殊用處的巨税,不用代碼生成蟋定,而是現(xiàn)成的代碼
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//沒(méi)有找到Adaptive類(lèi)型的實(shí)現(xiàn),動(dòng)態(tài)創(chuàng)建一個(gè)
//比如Protocol的實(shí)現(xiàn)類(lèi)草添,沒(méi)有任何一個(gè)實(shí)現(xiàn)是用@Adaptive來(lái)注解的驶兜,只有Protocol接口的方法是有注解的
//這時(shí)候就需要來(lái)動(dòng)態(tài)的生成了,也就是生成Protocol$Adaptive
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
加載擴(kuò)展類(lèi)實(shí)現(xiàn)
先看下getExtensionClasses()這個(gè)方法远寸,加載所有的擴(kuò)展類(lèi)的實(shí)現(xiàn):
private Map<String, Class<?>> getExtensionClasses() {
//從緩存中獲取促王,cachedClasses也是一個(gè)Holder,Holder這里持有的是一個(gè)Map而晒,key是擴(kuò)展點(diǎn)實(shí)現(xiàn)名,value是擴(kuò)展點(diǎn)實(shí)現(xiàn)類(lèi)
//這里會(huì)存放當(dāng)前擴(kuò)展點(diǎn)類(lèi)型的所有的擴(kuò)展點(diǎn)的實(shí)現(xiàn)類(lèi)
//這里以Protocol為例阅畴,就是會(huì)存放Protocol的所有實(shí)現(xiàn)類(lèi)
//比如key為dubbo倡怎,value為com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
//cachedClasses擴(kuò)展點(diǎn)實(shí)現(xiàn)名稱(chēng)對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)
Map<String, Class<?>> classes = cachedClasses.get();
//如果為null,說(shuō)明沒(méi)有被加載過(guò),就會(huì)進(jìn)行加載监署,而且加載就只會(huì)進(jìn)行這一次
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
//如果沒(méi)有加載過(guò)Extension的實(shí)現(xiàn)颤专,進(jìn)行掃描加載,完成后緩存起來(lái)
//每個(gè)擴(kuò)展點(diǎn)钠乏,其實(shí)現(xiàn)的加載只會(huì)這執(zhí)行一次
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
看下loadExtensionClasses()方法栖秕,這個(gè)方法中加載擴(kuò)展點(diǎn)的實(shí)現(xiàn)類(lèi):
private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if(defaultAnnotation != null) {
//當(dāng)前Extension的默認(rèn)實(shí)現(xiàn)名字
//比如說(shuō)Protocol接口,注解是@SPI("dubbo")
//這里dubbo就是默認(rèn)的值
String value = defaultAnnotation.value();
//只能有一個(gè)默認(rèn)的名字晓避,如果多了簇捍,誰(shuí)也不知道該用哪一個(gè)實(shí)現(xiàn)了。
if(value != null && (value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if(names.length > 1) {
throw new IllegalStateException();
}
//默認(rèn)的名字保存起來(lái)
if(names.length == 1) cachedDefaultName = names[0];
}
}
//下面就開(kāi)始從配置文件中加載擴(kuò)展實(shí)現(xiàn)類(lèi)
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
//從META-INF/dubbo/internal目錄下加載
loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
//從META-INF/dubbo/目錄下加載
loadFile(extensionClasses, DUBBO_DIRECTORY);
//從META-INF/services/下加載
loadFile(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
從各個(gè)位置的配置文件中加載實(shí)現(xiàn)類(lèi)俏拱,對(duì)于Protocol來(lái)說(shuō)加載的文件是以com.alibaba.dubbo.rpc.Protocol
為名稱(chēng)的文件暑塑,文件的內(nèi)容是(有好幾個(gè)同名的配置文件,這里直接把內(nèi)容全部寫(xiě)在了一起):
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
memcached=memcom.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol
rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
看下loadFile()方法:
private void loadFile(Map<String, Class<?>> extensionClasses, String dir) {
//配置文件的名稱(chēng)
//這里type是擴(kuò)展類(lèi)锅必,比如com.alibaba.dubbo.rpc.Protocol類(lèi)
String fileName = dir + type.getName();
try {
Enumeration<java.net.URL> urls;
//獲取類(lèi)加載器
ClassLoader classLoader = findClassLoader();
//獲取對(duì)應(yīng)配置文件名的所有的文件
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
//遍歷文件進(jìn)行處理
while (urls.hasMoreElements()) {
//配置文件路徑
java.net.URL url = urls.nextElement();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
try {
String line = null;
//每次處理一行
while ((line = reader.readLine()) != null) {
//#號(hào)以后的為注釋
final int ci = line.indexOf('#');
//注釋去掉
if (ci >= 0) line = line.substring(0, ci);
line = line.trim();
if (line.length() > 0) {
try {
String name = null;
//=號(hào)之前的為擴(kuò)展名字事格,后面的為擴(kuò)展類(lèi)實(shí)現(xiàn)的全限定名
int i = line.indexOf('=');
if (i > 0) {
name = line.substring(0, i).trim();
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
//加載擴(kuò)展類(lèi)的實(shí)現(xiàn)
Class<?> clazz = Class.forName(line, true, classLoader);
//查看類(lèi)型是否匹配
//type是Protocol接口
//clazz就是Protocol的各個(gè)實(shí)現(xiàn)類(lèi)
if (! type.isAssignableFrom(clazz)) {
throw new IllegalStateException();
}
//如果實(shí)現(xiàn)類(lèi)是@Adaptive類(lèi)型的,會(huì)賦值給cachedAdaptiveClass搞隐,這個(gè)用來(lái)存放被@Adaptive注解的實(shí)現(xiàn)類(lèi)
if (clazz.isAnnotationPresent(Adaptive.class)) {
if(cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (! cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException();
}
} else {//不是@Adaptice類(lèi)型的類(lèi)驹愚,就是沒(méi)有注解@Adaptive的實(shí)現(xiàn)類(lèi)
try {//判斷是否是wrapper類(lèi)型
//如果得到的實(shí)現(xiàn)類(lèi)的構(gòu)造方法中的參數(shù)是擴(kuò)展點(diǎn)類(lèi)型的,就是一個(gè)Wrapper類(lèi)
//比如ProtocolFilterWrapper劣纲,實(shí)現(xiàn)了Protocol類(lèi)逢捺,
//而它的構(gòu)造方法是這樣public ProtocolFilterWrapper(Protocol protocol)
//就說(shuō)明這個(gè)類(lèi)是一個(gè)包裝類(lèi)
clazz.getConstructor(type);
//cachedWrapperClasses用來(lái)存放當(dāng)前擴(kuò)展點(diǎn)實(shí)現(xiàn)類(lèi)中的包裝類(lèi)
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
} catch (NoSuchMethodException e) {
//沒(méi)有上面提到的構(gòu)造器,則說(shuō)明不是wrapper類(lèi)型
//獲取無(wú)參構(gòu)造
clazz.getConstructor();
//沒(méi)有名字味廊,就是配置文件中沒(méi)有xxx=xxxx.com.xxx這種
if (name == null || name.length() == 0) {
//去找@Extension注解中配置的值
name = findAnnotationName(clazz);
//如果還沒(méi)找到名字蒸甜,從類(lèi)名中獲取
if (name == null || name.length() == 0) {
//比如clazz是DubboProtocol,type是Protocol
//這里得到的name就是dubbo
if (clazz.getSimpleName().length() > type.getSimpleName().length()
&& clazz.getSimpleName().endsWith(type.getSimpleName())) {
name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
} else {
throw new IllegalStateException(");
}
}
}
//有可能配置了多個(gè)名字
String[] names = NAME_SEPARATOR.split(name);
if (names != null && names.length > 0) {
//是否是Active類(lèi)型的類(lèi)
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
//第一個(gè)名字作為鍵余佛,放進(jìn)cachedActivates這個(gè)map中緩存
cachedActivates.put(names[0], activate);
}
for (String n : names) {
if (! cachedNames.containsKey(clazz)) {
//放入Extension實(shí)現(xiàn)類(lèi)與名稱(chēng)映射的緩存中去柠新,每個(gè)class只對(duì)應(yīng)第一個(gè)名稱(chēng)有效
cachedNames.put(clazz, n);
}
Class<?> c = extensionClasses.get(n);
if (c == null) {
//放入到extensionClasses緩存中去,多個(gè)name可能對(duì)應(yīng)一份extensionClasses
extensionClasses.put(n, clazz);
} else if (c != clazz) {
throw new IllegalStateException();
}
}
}
}
}
}
} catch (Throwable t) { }
}
} // end of while read lines
} finally {
reader.close();
}
} catch (Throwable t) { }
} // end of while urls
}
} catch (Throwable t) { }
}
到這里加載當(dāng)前Extension的所有實(shí)現(xiàn)就已經(jīng)完成了辉巡,繼續(xù)返回getAdaptiveExtensionClass中恨憎,在調(diào)用完getExtensionClasses()之后,會(huì)首先檢查是不是已經(jīng)有@Adaptive注解的類(lèi)被解析并加入到緩存中了郊楣,如果有就直接返回憔恳,這里的cachedAdaptiveClass中現(xiàn)在只能是AdaptiveExtensionFactory或者AdaptiveCompiler中的一個(gè),如果沒(méi)有净蚤,說(shuō)明是一個(gè)普通擴(kuò)展點(diǎn)钥组,就動(dòng)態(tài)創(chuàng)建一個(gè),比如會(huì)創(chuàng)建一個(gè)Protocol$Adaptive
今瀑。
創(chuàng)建自適應(yīng)擴(kuò)展類(lèi)的代碼
看下createAdaptiveExtensionClass()這個(gè)方法程梦,用來(lái)動(dòng)態(tài)的創(chuàng)建自適應(yīng)擴(kuò)展類(lèi):
private Class<?> createAdaptiveExtensionClass() {
//組裝自適應(yīng)擴(kuò)展點(diǎn)類(lèi)的代碼
String code = createAdaptiveExtensionClassCode();
//獲取到應(yīng)用的類(lèi)加載器
ClassLoader classLoader = findClassLoader();
//獲取編譯器
//dubbo默認(rèn)使用javassist
//這里還是使用擴(kuò)展點(diǎn)機(jī)制來(lái)找具體的Compiler的實(shí)現(xiàn)
//現(xiàn)在就知道cachedAdaptiveClass是啥意思了点把,如果沒(méi)有AdaptiveExtensionFactory和AdaptiveCompiler這兩個(gè)類(lèi),這里又要去走加載流程然后來(lái)生成擴(kuò)展點(diǎn)類(lèi)的代碼屿附,不就死循環(huán)了么郎逃。
//這里解析Compiler的實(shí)現(xiàn)類(lèi)的時(shí)候,會(huì)在getAdaptiveExtensionClass中直接返回
//可以查看下AdaptiveCompiler這個(gè)類(lèi)挺份,如果我們沒(méi)有指定褒翰,默認(rèn)使用javassist
//這里Compiler是JavassistCompiler實(shí)例
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
//將代碼轉(zhuǎn)換成Class
return compiler.compile(code, classLoader);
}
接著看下createAdaptiveExtensionClassCode()方法,用來(lái)組裝自適應(yīng)擴(kuò)展類(lèi)的代碼(拼寫(xiě)源碼匀泊,代碼比較長(zhǎng)不在列出)优训,這里列出生成的Protocol$Adaptive
:
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {
if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker {
if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
public void destroy() {
throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
}
其他具體的擴(kuò)展點(diǎn)的生成也類(lèi)似。在生成完代碼之后探赫,是找到ClassLoader型宙,然后獲取到Compiler的自適應(yīng)實(shí)現(xiàn),這里得到的就是AdaptiveCompiler伦吠,最后調(diào)用compiler.compile(code, classLoader);
來(lái)編譯上面生成的類(lèi)并返回妆兑,先進(jìn)入AdaptiveCompiler的compile方法:
public Class<?> compile(String code, ClassLoader classLoader) {
Compiler compiler;
//得到一個(gè)ExtensionLoader
ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
//默認(rèn)的Compiler名字
String name = DEFAULT_COMPILER; // copy reference
//有指定了Compiler名字,就使用指定的名字來(lái)找到Compiler實(shí)現(xiàn)類(lèi)
if (name != null && name.length() > 0) {
compiler = loader.getExtension(name);
} else {//沒(méi)有指定Compiler名字毛仪,就查找默認(rèn)的Compiler的實(shí)現(xiàn)類(lèi)
compiler = loader.getDefaultExtension();
}
//調(diào)用具體的實(shí)現(xiàn)類(lèi)來(lái)進(jìn)行編譯
return compiler.compile(code, classLoader);
}
獲取指定名字的擴(kuò)展
先看下根據(jù)具體的名字來(lái)獲取擴(kuò)展的實(shí)現(xiàn)類(lèi)loader.getExtension(name);
搁嗓,loader是ExtensionLoader<Compiler>
類(lèi)型的。這里就是比Java的SPI要方便的地方箱靴,Java的SPI只能通過(guò)遍歷所有的實(shí)現(xiàn)類(lèi)來(lái)查找腺逛,而dubbo能夠指定一個(gè)名字查找。代碼如下:
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
//如果name指定為true衡怀,則獲取默認(rèn)實(shí)現(xiàn)
if ("true".equals(name)) {
//默認(rèn)實(shí)現(xiàn)查找在下面解析
return getDefaultExtension();
}
//先從緩存獲取Holder棍矛,cachedInstance是一個(gè)ConcurrentHashMap,鍵是擴(kuò)展的name抛杨,值是一個(gè)持有name對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)實(shí)例的Holder够委。
Holder<Object> holder = cachedInstances.get(name);
//如果當(dāng)前name對(duì)應(yīng)的Holder不存在,就創(chuàng)建一個(gè)怖现,添加進(jìn)map中
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
//從Holder中獲取保存的實(shí)例
Object instance = holder.get();
//不存在茁帽,就需要根據(jù)這個(gè)name找到實(shí)現(xiàn)類(lèi),實(shí)例化一個(gè)
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//緩存不存在屈嗤,創(chuàng)建實(shí)例
instance = createExtension(name);
//加入緩存
holder.set(instance);
}
}
}
//存在潘拨,就直接返回
return (T) instance;
}
創(chuàng)建擴(kuò)展實(shí)例,createExtension(name);
:
private T createExtension(String name) {
//getExtensionClasses加載當(dāng)前Extension的所有實(shí)現(xiàn)
//上面已經(jīng)解析過(guò)饶号,返回的是一個(gè)Map铁追,鍵是name,值是name對(duì)應(yīng)的Class
//根據(jù)name查找對(duì)應(yīng)的Class
Class<?> clazz = getExtensionClasses().get(name);
//如果這時(shí)候class還不存在茫船,說(shuō)明在所有的配置文件中都沒(méi)找到定義脂信,拋異常
if (clazz == null) {
throw findException(name);
}
try {
//從已創(chuàng)建實(shí)例緩存中獲取
T instance = (T) EXTENSION_INSTANCES.get(clazz);
//不存在的話就創(chuàng)建一個(gè)新實(shí)例癣蟋,加入到緩存中去
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//屬性注入
injectExtension(instance);
//Wrapper的包裝
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) { }
}
有關(guān)屬性注入和Wrapper的包裝,下面再講狰闪。到這里Compiler就能獲得到一個(gè)指定name的具體實(shí)現(xiàn)類(lèi)的實(shí)例了,然后就是調(diào)用實(shí)例的compile()方法對(duì)生成的代碼進(jìn)行編譯濒生。
獲取默認(rèn)擴(kuò)展實(shí)現(xiàn)
如果在AdaptiveCompiler中沒(méi)有找到指定的名字埋泵,就會(huì)找默認(rèn)的擴(kuò)展實(shí)現(xiàn)loader.getDefaultExtension();
:
public T getDefaultExtension() {
//首先還是先去加載所有的擴(kuò)展實(shí)現(xiàn)
//加載的時(shí)候會(huì)設(shè)置默認(rèn)的名字cachedDefaultName,這個(gè)名字是在@SPI中指定的罪治,比如Compiler就指定了@SPI("javassist")丽声,所以這里是javassist
getExtensionClasses();
if(null == cachedDefaultName || cachedDefaultName.length() == 0
|| "true".equals(cachedDefaultName)) {
return null;
}
//根據(jù)javassist這個(gè)名字去查找擴(kuò)展實(shí)現(xiàn)
//具體的過(guò)程上面已經(jīng)解析過(guò)了
return getExtension(cachedDefaultName);
}
關(guān)于javassist編譯Class的過(guò)程暫先不說(shuō)明。我們接著流程看:
private T createAdaptiveExtension() {
try {
//先通過(guò)getAdaptiveExtensionClass獲取AdaptiveExtensionClass(在上面這一步已經(jīng)解析了觉义,獲得到了一個(gè)自適應(yīng)實(shí)現(xiàn)類(lèi)的Class)
//然后獲取其實(shí)例雁社,newInstance進(jìn)行實(shí)例
//最后進(jìn)行注入處理injectExtension
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) { }
}
擴(kuò)展點(diǎn)注入
接下來(lái)就是有關(guān)擴(kuò)展點(diǎn)的注入的問(wèn)題了,injectExtension晒骇,關(guān)于注入的解釋查看最上面擴(kuò)展點(diǎn)自動(dòng)裝配(IOC)的說(shuō)明霉撵,injectExtension方法:
//這里的實(shí)例是Xxxx$Adaptive
private T injectExtension(T instance) {
try {
//關(guān)于objectFactory的來(lái)路,先看下面的解析
//這里的objectFactory是AdaptiveExtensionFactory
if (objectFactory != null) {
//遍歷擴(kuò)展實(shí)現(xiàn)類(lèi)實(shí)例的方法
for (Method method : instance.getClass().getMethods()) {
//只處理set方法
//set開(kāi)頭洪囤,只有一個(gè)參數(shù)徒坡,public
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
//set方法參數(shù)類(lèi)型
Class<?> pt = method.getParameterTypes()[0];
try {
//setter方法對(duì)應(yīng)的屬性名
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
//根據(jù)類(lèi)型和名稱(chēng)信息從ExtensionFactory中獲取
//比如在某個(gè)擴(kuò)展實(shí)現(xiàn)類(lèi)中會(huì)有setProtocol(Protocol protocol)這樣的set方法
//這里pt就是Protocol,property就是protocol
//AdaptiveExtensionFactory就會(huì)根據(jù)這兩個(gè)參數(shù)去查找對(duì)應(yīng)的擴(kuò)展實(shí)現(xiàn)類(lèi)
//這里就會(huì)返回Protocol$Adaptive
Object object = objectFactory.getExtension(pt, property);
if (object != null) {//說(shuō)明set方法的參數(shù)是擴(kuò)展點(diǎn)類(lèi)型瘤缩,進(jìn)行注入
//為set方法注入一個(gè)自適應(yīng)的實(shí)現(xiàn)類(lèi)
method.invoke(instance, object);
}
} catch (Exception e) { }
}
}
}
} catch (Exception e) {}
return instance;
}
有關(guān)AdaptiveExtensionFactory中獲取Extension的過(guò)程喇完,會(huì)首先在實(shí)例化的時(shí)候得到ExtensionFactory的具體實(shí)現(xiàn)類(lèi),然后遍歷每個(gè)ExtensionFactory的實(shí)現(xiàn)類(lèi)剥啤,分別在每個(gè)ExtensionFactory的實(shí)現(xiàn)類(lèi)中獲取Extension锦溪。
這里使用SpiExtensionFactory的獲取擴(kuò)展的方法為例,getExtension府怯,也是先判斷給定類(lèi)是否是注解了@SPI的接口刻诊,然后根據(jù)類(lèi)去獲取ExtensionLoader,在使用得到的ExtensionLoader去加載自適應(yīng)擴(kuò)展富腊。
objectFactory的來(lái)歷
objectFactory的來(lái)路坏逢,在ExtensionLoader中有個(gè)私有構(gòu)造器:
//當(dāng)我們調(diào)用getExtensionLoader這個(gè)靜態(tài)方法的時(shí)候,會(huì)觸發(fā)ExtensionLoader類(lèi)的實(shí)例化赘被,會(huì)先初始化靜態(tài)變量和靜態(tài)塊是整,然后是構(gòu)造代碼塊,最后是構(gòu)造器的初始化
private ExtensionLoader(Class<?> type) {
this.type = type;
//這里會(huì)獲得一個(gè)AdaptiveExtensionFactory
//根據(jù)類(lèi)型和名稱(chēng)信息從ExtensionFactory中獲取
//獲取實(shí)現(xiàn)
//為什么要使用對(duì)象工廠來(lái)獲取setter方法中對(duì)應(yīng)的實(shí)現(xiàn)民假?
//不能通過(guò)spi直接獲取自適應(yīng)實(shí)現(xiàn)嗎浮入?比如ExtensionLoader.getExtension(pt);
//因?yàn)閟etter方法中有可能是一個(gè)spi,也有可能是普通的bean
//所以此時(shí)不能寫(xiě)死通過(guò)spi獲取羊异,還需要有其他方式來(lái)獲取實(shí)現(xiàn)進(jìn)行注入
// dubbo中有兩個(gè)實(shí)現(xiàn)事秀,一個(gè)是spi的ExtensionFactory彤断,一個(gè)是spring的ExtensionFactory
//如果還有其他的,我們可以自定義ExtensionFactory
//objectFactory是AdaptiveExtensionFactory實(shí)例
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
到此為止createAdaptiveExtension方法解析完成易迹,接著返回上層getAdaptiveExtension()方法中宰衙,發(fā)現(xiàn)創(chuàng)建完自適應(yīng)擴(kuò)展實(shí)例之后,就會(huì)加入到cachedAdaptiveInstance緩存起來(lái)睹欲,然后就會(huì)返回給調(diào)用的地方一個(gè)Xxx$Adaptive
實(shí)例供炼。
走到這里,下面的代碼就解析完了:
private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
得到擴(kuò)展之后的使用
我們得到了一個(gè)Protocol$Adaptive
實(shí)例窘疮,接著就是調(diào)用了袋哼,比如說(shuō)我們要調(diào)用refprotocol.refer(Class<T> type, URL url))
方法,由于這里refprotocol是一個(gè)Protocol$Adaptive
實(shí)例闸衫,所以就先調(diào)用這個(gè)實(shí)例的refer方法涛贯,這里的實(shí)例的代碼在最上面:
//這里為了好看,代碼做了精簡(jiǎn)蔚出,包名都去掉了
public Invoker refer(Class arg0, URL arg1) throws Class {
if (arg1 == null) throw new IllegalArgumentException();
URL url = arg1;
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException();
Protocol extension = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
可以看到這里首先根據(jù)url中的參數(shù)獲取擴(kuò)展名字弟翘,如果url中沒(méi)有就使用默認(rèn)的擴(kuò)展名,然后根據(jù)擴(kuò)展名去獲取具體的實(shí)現(xiàn)身冬。關(guān)于getExtension(String name)上面已經(jīng)解析過(guò)一次衅胀,這里再次列出:
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
//如果name指定為true,則獲取默認(rèn)實(shí)現(xiàn)
if ("true".equals(name)) {
//默認(rèn)實(shí)現(xiàn)查找在下面解析
return getDefaultExtension();
}
//先從緩存獲取Holder酥筝,cachedInstance是一個(gè)ConcurrentHashMap滚躯,鍵是擴(kuò)展的name,值是一個(gè)持有name對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)實(shí)例的Holder嘿歌。
Holder<Object> holder = cachedInstances.get(name);
//如果當(dāng)前name對(duì)應(yīng)的Holder不存在顶岸,就創(chuàng)建一個(gè)益眉,添加進(jìn)map中
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
//從Holder中獲取保存的實(shí)例
Object instance = holder.get();
//不存在,就需要根據(jù)這個(gè)name找到實(shí)現(xiàn)類(lèi),實(shí)例化一個(gè)
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//緩存不存在愈腾,創(chuàng)建實(shí)例
instance = createExtension(name);
//加入緩存
holder.set(instance);
}
}
}
//存在笔喉,就直接返回
return (T) instance;
}
創(chuàng)建擴(kuò)展實(shí)例堡僻,createExtension(name);
:
private T createExtension(String name) {
//getExtensionClasses加載當(dāng)前Extension的所有實(shí)現(xiàn)
//上面已經(jīng)解析過(guò)观谦,返回的是一個(gè)Map,鍵是name靴患,值是name對(duì)應(yīng)的Class
//根據(jù)name查找對(duì)應(yīng)的Class
//比如name是dubbo仍侥,Class就是com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
Class<?> clazz = getExtensionClasses().get(name);
//如果這時(shí)候class還不存在,說(shuō)明在所有的配置文件中都沒(méi)找到定義鸳君,拋異常
if (clazz == null) {
throw findException(name);
}
try {
//從已創(chuàng)建實(shí)例緩存中獲取
T instance = (T) EXTENSION_INSTANCES.get(clazz);
//不存在的話就創(chuàng)建一個(gè)新實(shí)例农渊,加入到緩存中去
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//這里實(shí)例就是具體實(shí)現(xiàn)的實(shí)例了比如是DubboProtocol的實(shí)例
//屬性注入,在上面已經(jīng)解析過(guò)了或颊,根據(jù)實(shí)例中的setXxx方法進(jìn)行注入
injectExtension(instance);
//Wrapper的包裝
//cachedWrapperClasses存放著所有的Wrapper類(lèi)
//cachedWrapperClasses是在加載擴(kuò)展實(shí)現(xiàn)類(lèi)的時(shí)候放進(jìn)去的
//Wrapper類(lèi)的說(shuō)明在最上面擴(kuò)展點(diǎn)自動(dòng)包裝(AOP)
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
for (Class<?> wrapperClass : wrapperClasses) {
//比如在包裝之前的instance是DubboProtocol實(shí)例
//先使用構(gòu)造器來(lái)實(shí)例化當(dāng)前的包裝類(lèi)
//包裝類(lèi)中就已經(jīng)包含了我們的DubboProtocol實(shí)例
//然后對(duì)包裝類(lèi)進(jìn)行injectExtension注入砸紊,注入過(guò)程在上面
//最后返回的Instance就是包裝類(lèi)的實(shí)例传于。
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
//這里返回的是經(jīng)過(guò)所有的包裝類(lèi)包裝之后的實(shí)例
return instance;
} catch (Throwable t) { }
}
獲取的Extension是經(jīng)過(guò)層層包裝的擴(kuò)展實(shí)現(xiàn),然后就是調(diào)用經(jīng)過(guò)包裝的refer方法了醉顽,這就到了具體的實(shí)現(xiàn)中的方法了沼溜。
到此為止調(diào)用refprotocol.refer(Class<T> type, URL url))
方法的過(guò)程也解析完了。
關(guān)于getActivateExtension方法的解析徽鼎,等下再添加盛末。