關於@Adaptive注解
引用dubbo官方文檔的一段話:
Adaptive 可注解在類或方法上。當 Adaptive 注解在類上時,Dubbo 不會為該類生成代理類。注解在方法(接口方法)上時,Dubbo 則會為該方法生成代理邏輯。Adaptive 注解在類上的情況很少,在 Dubbo 中,僅有兩個類被 Adaptive 注解了,分別是 AdaptiveCompiler 和 AdaptiveExtensionFactory。此種情況,表示拓展的加載邏輯由人工編碼完成。更多時候,Adaptive 是注解在接口方法上的,表示拓展的加載邏輯需由框架自動生成。
為什么要設計adaptive?注解在類上和注解在方法上的區別?
adaptive設計的目的是為了識別固定已知類和擴展未知類。
-
注解在類上:代表人工實現,實現一個裝飾類(設計模式中的裝飾模式),它主要作用於固定已知類,
目前整個系統只有2個, AdaptiveCompiler,AdaptiveExtensionFactory
- 為什么AdaptiveCompiler這個類是固定已知的?因為整個框架僅支持Javassist和JdkCompiler。
- 為什么AdaptiveExtensionFactory這個類是固定已知的?因為整個框架僅支持2個objFactory,一個是spi,另一個是spring
-
注解在方法上:代表自動生成和編譯一個動態的Adpative類,它主要是用於SPI,因為spi的類是不固定、未知的擴展類,所以設計了動態$Adaptive類.
例如 Protocol的spi類有 injvm dubbo registry filter listener等等 很多擴展未知類,
它設計了Protocol$Adaptive的類,通過ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(spi類);來提取對象
一、在接口上
在接口上,在調用getAdaptiveExtension方法時,直接返回該類(不會去動態生成代理類),然后執行IOC
二、在方法上
在方法上會生成代理代理類
關於createAdaptiveExtensionClassCode方法
-
至少有一個方法被@Adaptive修飾
-
被@Adaptive修飾得方法得參數 必須滿足參數中有一個是URL類型,或者有至少一個參數有一個“公共且非靜態的返回URL的無參get方法”
-
@Adaptive注解中的值這里我叫它value,value可以是一個數組,如果為空的話,vlaue等於接口名小寫(例如接口名:per.qiao.A, 那么value=a)
獲取擴展名圖如下:
這里value表示@Adaptive注解的值(數組)中最后一個value, 如果該數組為空,則value等於接口名小寫
java生成動態類的模板
java生成動態類的模板
package <擴展點接口所在包>;
public class <擴展點接口名>$Adpative implements <擴展點接口> {
public <有@Adaptive注解的接口方法>(<方法參數>) {
if(是否有URL類型方法參數?) 使用該URL參數
else if(是否有方法類型上有URL屬性) 使用該URL屬性
<else 在加載擴展點生成自適應擴展點類時拋異常,即加載擴展點失敗!>
if(獲取的URL == null) {
throw new IllegalArgumentException("url == null");
}
//...獲取擴展點名 圖解如上
<接口> extension = (接口) ExtensionLoader.getExtensionLoader(接口).getExtension(擴展點名);
extension.<有@Adaptive注解的接口方法>(<方法參數>)
}
public <無@Adaptive注解的接口方法>(<方法參數>) {
throw new UnsupportedOperationException("is not adaptive method!");
}
}
小結:
-
一個擴展文件內只能有一個擴展類被@Adaptive修飾,而且還需要有其他的初@Adaptive和AOP擴展之外的至少一個其他擴展
-
@Adaptive如果方在類上,那么cachedAdaptiveClass就等於該類
Holder