dubbo源碼閱讀之spi

為什么要設計adaptive?注解在類上和注解在方法上的區(qū)別?

adaptive設計的目的是為了識別固定已知類和擴展未知類。

1.注解在類上:代表人工實現(xiàn),實現(xiàn)一個裝飾類(設計模式中的裝飾模式),它主要作用于固定已知類,

? 目前整個系統(tǒng)只有2個,AdaptiveCompiler、AdaptiveExtensionFactory。

? a.為什么AdaptiveCompiler這個類是固定已知的?因為整個框架僅支持Javassist和JdkCompiler。

? b.為什么AdaptiveExtensionFactory這個類是固定已知的?因為整個框架僅支持2個objFactory,一個是spi,另一個是spring

2.注解在方法上:代表自動生成和編譯一個動態(tài)的Adpative類,它主要是用于SPI,因為spi的類是不固定、未知的擴展類,所以設計了動態(tài)$Adaptive類.

例如 Protocol的spi類有 injvm dubbo registry filter listener等等 很多擴展未知類,

它設計了Protocol$Adaptive的類,通過ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(spi類);來提取對象

為什么dubbo要自己設計一套SPI?

這是原始JDK spi的代碼

ServiceLoader<Command> serviceLoader=ServiceLoader.load(Command.class);?

? for(Command command:serviceLoader){??

? ? ? command.execute();??

? }??

dubbo在原來的基礎上設計了以下功能

1.原始JDK spi不支持緩存;dubbo設計了緩存對象:spi的key與value 緩存在 cachedInstances對象里面,它是一個ConcurrentMap

2.原始JDK spi不支持默認值,dubbo設計默認值:@SPI("dubbo") 代表默認的spi對象,例如Protocol的@SPI("dubbo")就是 DubboProtocol,

? 通過 ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension()那默認對象

3.jdk要用for循環(huán)判斷對象,dubbo設計getExtension靈活方便,動態(tài)獲取spi對象,

? 例如 ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(spi的key)來提取對象

4.原始JDK spi不支持 AOP功能,dubbo設計增加了AOP功能,在cachedWrapperClasses,在原始spi類,包裝了XxxxFilterWrapper XxxxListenerWrapper

5.原始JDK spi不支持 IOC功能,dubbo設計增加了IOC,通過構造函數(shù)注入,代碼為:wrapperClass.getConstructor(type).newInstance(instance),

dubbo spi 的目的:獲取一個指定實現(xiàn)類的對象。

途徑:ExtensionLoader.getExtension(String name)

實現(xiàn)路徑:

getExtensionLoader(Class<T> type) 就是為該接口new 一個ExtensionLoader,然后緩存起來。

getAdaptiveExtension() 獲取一個擴展類,如果@Adaptive注解在類上就是一個裝飾類;如果注解在方法上就是一個動態(tài)代理類,例如Protocol$Adaptive對象。

getExtension(String name) 獲取一個指定對象。

-----------------------ExtensionLoader.getExtensionLoader(Class<T> type)

ExtensionLoader.getExtensionLoader(Container.class)

? -->this.type = type;

? -->objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());

? ? ?-->ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()

? ? ? ?-->this.type = type;

? ? ? ?-->objectFactory =null;


執(zhí)行以上代碼完成了2個屬性的初始化

1.每個一個ExtensionLoader都包含了2個值 type 和 objectFactory

? Class<?> type;//構造器? 初始化時要得到的接口名

? ExtensionFactory objectFactory//構造器? 初始化時 AdaptiveExtensionFactory[SpiExtensionFactory,SpringExtensionFactory]

2.new 一個ExtensionLoader 存儲在ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS

關于這個objectFactory的一些細節(jié):

1.objectFactory就是ExtensionFactory,它也是通過ExtensionLoader.getExtensionLoader(ExtensionFactory.class)來實現(xiàn)的,但是它的objectFactory=null

2.objectFactory作用,它就是為dubbo的IOC提供所有對象。


-----------------------getAdaptiveExtension()

-->getAdaptiveExtension()//為cachedAdaptiveInstance賦值

? -->createAdaptiveExtension()

? ? -->getAdaptiveExtensionClass()

? ? ? -->getExtensionClasses()//為cachedClasses 賦值

? ? ? ? -->loadExtensionClasses()

? ? ? ? ? -->loadFile

? ? ? -->createAdaptiveExtensionClass()//自動生成和編譯一個動態(tài)的adpative類,這個類是一個代理類

? ? ? ? -->ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension()

? ? ? ? -->compiler.compile(code, classLoader)

? ? -->injectExtension()//作用:進入IOC的反轉(zhuǎn)控制模式,實現(xiàn)了動態(tài)入注



關于loadfile的一些細節(jié)

目的:通過把配置文件META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol的內(nèi)容,存儲在緩存變量里面。

cachedAdaptiveClass//如果這個class含有adative注解就賦值,例如ExtensionFactory,而例如Protocol在這個環(huán)節(jié)是沒有的。

cachedWrapperClasses//只有當該class無adative注解,并且構造函數(shù)包含目標接口(type)類型,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?例如protocol里面的spi就只有ProtocolFilterWrapper和ProtocolListenerWrapper能命中

cachedActivates//剩下的類,包含Activate注解

cachedNames//剩下的類就存儲在這里。

-----------------------getExtension(String name)

getExtension(String name) //指定對象緩存在cachedInstances;get出來的對象wrapper對象,例如protocol就是ProtocolFilterWrapper和ProtocolListenerWrapper其中一個。

? -->createExtension(String name)

? ? -->getExtensionClasses()

? ? -->injectExtension(T instance)//dubbo的IOC反轉(zhuǎn)控制,就是從spi和spring里面提取對象賦值。

? ? ? -->objectFactory.getExtension(pt, property)

? ? ? ? -->SpiExtensionFactory.getExtension(type, name)

? ? ? ? ? -->ExtensionLoader.getExtensionLoader(type)

? ? ? ? ? -->loader.getAdaptiveExtension()

? ? ? ? -->SpringExtensionFactory.getExtension(type, name)

? ? ? ? ? -->context.getBean(name)

? ? -->injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))//AOP的簡單設計

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 他們說:生活是你擺脫不了,又一直在堅持的。我不置可否,事情沒有絕對的對錯,做好我現(xiàn)在做的,同時又為想做的做好打算。...
    詩篇_8221閱讀 221評論 0 2
  • 一斷詞,一錯字,一如往事逝 一葦渡來寒江釣,笑嘆風來遲 一秋至,一衣織,一夜卷滿詩 一夢乍醒北窗亂,只道風不癡
    北城月閱讀 396評論 0 3
  • 母親,這個讓我歡喜讓我躲的人, 雖然寫的最多的是愛情,前幾年天天在說母愛的偉大,現(xiàn)在確感覺無人提起, 誤以為...
    站在屋頂歌唱閱讀 153評論 0 0

友情鏈接更多精彩內(nèi)容