1. 程式人生 > >Dubbo概述--啟動過程

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和服務類介面