Dubbo源碼分析(五)ExtensionLoader

ExtensionLoader是Dubbo中很有特色的一個設計,它的作用是爲框架提供各種組件的擴展點,可以在應用運行時來決定使用哪個組件。對擴展點組件的描述是通過註解的方式實現的,包括3個主要的註解:

  • SPI
  • Adaptive
  • Activate

我們先從註解的含義來理解ExtensionLoader

SPI

SPI是一個很早就存在的概念,它是預先定義的一組接口,並允許各個廠商(使用方)有自己的實現,通過配置的方式在運行時決定使用哪種實現。我們可以看一下Dubbo中具有SPI標記的接口有哪些

  1. CacheFactory
  2. Compiler
  3. ExtensionFactory
  4. LoggerAdapter
  5. Serialization
  6. StatusChecker
  7. DataStore
  8. ThreadPool
  9. Container
  10. PageHandler
  11. MonitorFactory
  12. RegistryFactory
  13. ChannelHandler
  14. Codec
  15. Codec2
  16. Dispatcher
  17. Transporter
  18. Exchanger
  19. HttpBinder
  20. Networker
  21. TelnetHandler
  22. ZookeeperTransporter
  23. ExporterListener
  24. Filter
  25. InvokerListener
  26. Protocol
  27. ProxyFactory
  28. Cluster
  29. ConfiguratorFactory
  30. LoadBalance
  31. Merger
  32. RouterFactory
  33. RuleConverter
  34. ClassNameGenerator
  35. Validation

當我們需這些接口的實現類時,就可以通過ExtensionLoader的方法獲取

其中第一個方法是拿到一個具體的實現類,第二個方法是拿到一組被激活的實現類。

Adaptive

這個詞無論作爲註解名還是get方法名都比較令人迷惑。Adaptive的本意是適配的,之所以這樣命名是因爲我們從getAdaptiveExtension()獲取到的對象並不是某個真正的實現類,而是對實現類進行封裝之後的一個適配器。當我們調用這個適配器的方法時,它會間接地去調用具體實現類的方法。而適配器中正包含了該選取何種實現方式的邏輯。

適配器類的定義有兩種來源:

  1. 靜態代碼形式的默認適配器。這些類會被Adaptive註解修飾,且一個接口只能有一個這樣的靜態適配器。這種形式僅應用於一些特殊的接口,如:AdaptiveCompiler、AdaptiveExtensionFactory這兩個適配器,ExtensionLoader需要依賴它們來工作,所以使用了這種特殊的構建方式。
  2. 動態代碼適配器。實際上其餘的接口都是使用動態適配器,ExtensionLoader根據接口定義動態生成一段適配器代碼,並構建這個動態類的實例。這個時候接口中的一些方法具有Adaptive標記,它提供了一些用於查找具體Extension的key,如果這些方法中有URL類型的參數,則會依次在url中查找這些key對應的value,再以此爲name確定要使用的Extension。如果沒有從url中找到該參數,則會使用SPI註解中的默認值name進行構建。

Transporter

下面以Transporter接口爲例進行說明

bind方法具有Adaptive標記,所以在生成動態Adapter類的時候,該方法會根據運行時的參數決定使用那個具體的實現類,以下是部分動態類的代碼

在適配器的方法中,首先要確定具體實現類的類型,也就是extName。當方法中有URL類型的參數時,這個配置會從url參數中獲取。Adaptive註解中的兩個key即是在url查找的key,分別爲server和transporter。當兩個key都不存在時,使用SPI註解中得默認值netty。在確定了extName後,就可以從事先加載好的實例中獲取extension對象,最終將方法的調用傳遞給extension的對應方法。

全部extName與實現類的對應關係配置在dubbo jar包中MET-INF/dubbo/internal下,Transporter對應的配置文件爲

Activate

Activate標記適用於另外一種動態配置

一個接口有多個實現類,Activate標記在每個實現類的type上,並註明“何時被激活”的條件,如group和key的信息,以及在所有被激活實現類中的排序信息。通過ExtensionLoader的getActivateExtension可以獲取到被激活實現類構成的List。下面以最重要的Filter接口進行說明

接口本身不再有Activate註解,而是在它的實現類上面,如TimeoutFilter

只有在group爲provider時纔會生效

MonitorFilter在provider和consumer兩端都會生效。這裏group、key等條件是通過getActivateExtension的方法參數確定的,group通常是預先設定好的,key可以直接指定,也可以動態由url參數決定。當url中包含特定的key(value可以是任意值)時,對應的實例就會被激活。

ExtensionLoader本身還有很多複雜的實現細節,這裏就不再介紹了。感興趣的讀者可以翻閱源碼深入研究一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章