Dubbo概述--啓動過程

Dubbo–啓動過程

寫在前面

本文參考了Dubbo官方手冊結合Dubbo2.6.1版本源碼分析。推薦先閱讀官方手冊

鑑於個人水平有限,如有不正確的地方請指出,歡迎一起討論,謝謝!

啓動過程

啓動過程主要從Provider和Consumer進行分析。每個Provider最終會實例化爲一個ServiceBean的實例,而每個Consumer通過實現自FactoryBean接口的ReferenceBean在首次調用時創建代理實例(也可以通過init屬性設置非延遲加載)。

Provier啓動過程(暴露服務)

Provider的啓動過程默認由afterProperties方法觸發,也可以通過Spring的刷新事件觸發或者定時觸發(通過delay屬性控制),不需要通過代碼getBean即可完成Provider的啓動。

整個啓動過程圍繞兩個URL,一個是調用服務的URL,另一個是同Registry通信的URL。在整個啓動過程中通過向URL添加、讀取屬性(主要是Protocol)、參數,來串聯起整個過程中的擴展(Trasport/Protocol等)的指定和啓動的處理邏輯。

完成啓動步驟(ServiceConfig.doExport()方法)概述如下:

  1. 檢查並設置exported屬性

  2. 檢查默認配置,即檢查provider屬性是否爲空,爲空則實例化一個。

  3. 依照provider->module->application的順序設置自身爲空的屬性(說明自身設置優先級高,且配置優先級privider>module>application)。

  4. 檢查Provider提供服務的接口是否有服務方法以及接口實現類是否實現自接口。

  5. 檢查application、registry、protocol配置,如果對應對象不存在則進行處理。

  6. 對本對象進行屬性設置,屬性值來源於-D或者properties配置文件,優先-D。

  7. 檢查stub、local、mock配置,類是非存在、配飾是否合法、執行的構造器是否存在等。

    • stub,在客戶端執行,用於客戶端調用服務端時進行調用預處理或異常處理。相當於服務端對客戶端的要求,客戶端在調用時使用的是stub類。
    • local,已廢棄,被stub取代。
    • mock,在客戶端執行,專門用於調用服務端發生異常時進行異常處理。
  8. 設置服務類的路徑

  9. 基於各個Registry的配置,構造各個Registry的訪問URL

    • 將application、registry中帶有Parameter註解方法的key、value作爲參數添加到URL中。
    • 將application、registry中getParameters方法返回的Map中的key、value作爲參數添加到URL中。
    • 將path(訪問路徑)、dubbo(dubbo版本)、timestamp(URL構建時間)添加到URL中。
    • URL基本的protocol:IP:port三個部分優先使用registry的值,沒有則使用默認的:dubbo和9090,IP部分必須指定。
    • 設置URL的protocol部分爲registry,將實際的protocol以name爲registry,value爲實際protocol值的方式添加到URL參數部分。
  10. 根據配置構造服務Bean自身被調用時的訪問URL

    • 添加固定參數:side、dubbo、timestamp、pid
    • 將application、module、provider、protocolConfig以及自身中帶有Parameter註解方法的key、value作爲參數添加到URL中。
    • 將application、module、provider、protocolConfig中getParameters方法返回的Map中的key、value作爲參數添加到URL中。
    • 如果Provider內部有Method配置,則根據method配置添加帶有Parameter註解方法和getParameters方法返回的Map的key、value到URL參數中。
    • 嘗試添加可能存在的固定參數:generic、revision、token
    • 從Provider的接口中獲取所有的方法,以逗號分隔的方式添加到名爲methods的參數上。此處的參數名爲methods而根據Method配置添加的相關URL參數並不是此參數名且接口中的方法參數不會體現在URL參數列表中
  11. 根據scope屬性的配置決定代表Provider的URL註冊到Registry還是Local或者兩者都註冊或都不註冊。

  12. 如果需要將服務導出爲本地,則進行如下處理:

    • 修改Provider的調用URL,修改protocol爲injvm、host爲127.0.0.1、port爲0
    • 將Provider實際提供類保存到ThreadLocal中
    • 使用JavassistProxyFactory通過Wrapper類動態生成Wrapper類的子類,作爲AbstractProxyInvoker類doInvoke方法的實際處理類
    • 由於之前已經將protocol修改爲injvm,所以通過InjvmProtocol的export方法導出,生成InjvmExporter
    • 將導出的InjvmExporter添加到ServiceConfig.exporters集合中
  13. 如果需要將服務導出到註冊中心,則進行如下處理:

    • 根據配置向Provider調用URL中添加dynamic以及monitor相關參數值

    • 使用JavassistProxyFactory通過Wrapper類動態生成Wrapper類的子類,作爲AbstractProxyInvoker類doInvoke方法的實際處理類。此Invoker和本地導出的Invoker是相同的的類

    • 將上一步返回的Invoker和服務配置包裝爲DelegateProviderMetaDataInvoker類

    • 由於之前JavassistProxyFactory返回的AbstractProxyInvoker中,URL的Protocol爲Registry,所以使用RegistryProtocol的export方法導出,生成DestroyableExporter

    • RegistryProtocol首先根據服務調用URL調用其對應的Protocol的export打開本地服務,服務處理類根據不同的Protocol包裝爲不同的類,但都最終會調用到之前的Invoker類

    Provider Protocol 服務 服務處理類
    dubbo netty(grizzly/mima/netty4) – Transport服務擴展 DubboProtocol.ExchangeHandlerAdapter
    RMI Spring內嵌的RmiServiceExporter 直接使用Invoker類
    hessian jetty(Servlet/Tomcat) – HttpBinder服務擴展 HessianProtocol.HessianHandler
    injvm JVM內部調用
    • RegistryProtocol內部處理ProviderURL和RegistryURL,刪除不必要的參數等

    • 通過RegistryProtocol內部注入的RegistryFactory(ExtensionLoader注入實現)獲得Registry對象,進而向Registry註冊ProviderURL

    Registry Protocol Registry Description
    dubbo Simple Registry Registry本身是一個RPC服務者,通過文件保存Provider信息
    multicast 通過使用JDK自帶的廣播功能實現自動發現
    redis Redis 通過Redis自身的可靠性保證
    zookeeper Zookeeper 通過Zookeeper自身的可靠性保證
    mockregistry 只是用於測試打樁
    • 使用ProviderConsumerRegTable緩存Provider信息並設置爲已經註冊

    • 向註冊中心訂閱註冊一個監控服務配置改變的監聽器OverrideListener。

Consumer啓動過程(引用服務)

Consumer啓動實際上是ReferenceBean中getObject獲取代理類的過程。ReferenceConfig.init()方法

  1. 檢查Consumer默認配置,沒有則初始化一個並對屬性賦值。
  2. 加載服務接口類,並檢查接口類和其內部方法
  3. 優先嚐試從userHome目錄下的dubbo-resolve.properties文件中根據接口名獲取其調用URL
  4. 依照consumer->module->application的順序設置自身爲空的屬性(說明自身設置優先級高,且配置優先級consumer>module>application)。
  5. 檢查application配置
  6. 檢查stub、local、mock配置,類是非存在、配飾是否合法、執行的構造器是否存在等。
    • stub,在客戶端執行,用於客戶端調用服務端時進行調用預處理或異常處理。相當於服務端對客戶端的要求,客戶端在調用時使用的是stub類。
    • local,已廢棄,被stub取代。
    • mock,在客戶端執行,專門用於調用服務端發生異常時進行異常處理。
  7. 將application、consumer、module以及side、dubbo版本等信息存放到map中
  8. 首先判斷是否從JVM本地調用服務,如果是本地,則直接生成本地調用URL以及根據URL生成本地調用Invoker(InjvmInvoker)
  9. 如果不是本地調用,則判斷之前從dubbo-resolve.properties文件中是否根據接口名加載到了服務URL,如果有則直接到第11步
  10. 如果沒有從文件中加載到了服務URL,則加載所有的Registry配置獲取所有的Registry訪問URL
  11. 根據解析出的URL實例化Invoker
    • 如果只有一個URL則直接根據URL獲取Protocol,進而向Registry發佈自身相關信息(Consumer、Router),以及訂閱Provider、Configuration、Router信息。最終獲取Invoker(此Invoker內包含Cluster處理方式以及Directory)
    • 如果有多個URL則逐個按照一個URL的方式處理,然後將多個Invoker通過StaticDirectory組織後由Cluster組合爲一個Invoker
  12. 將Cluster組織好的Invoker通過ProxyFactory動態生成Consumer端的代理類,供Consumer調用。這個通過Javassist生成的動態代理類一般情況下會實現EchoService和服務類接口
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章