dubbo服務引用源碼分析

dubbo服務引用流程大致如下:

(1)首先在dubbo容器啓動的時候,會掃描所有的reference配置(也就是dubbo客戶端配置的遠程引用),生成對應ReferenceBean,例如:客戶端的DemoClient類依賴了遠程服務DemoService,那麼dubbo就會生成一個ReferenceBean<DemoService>

(2)spring容器在初始化本地的bean的時候,發現DemoClient類依賴了DemoService類,於是spring會尋找DemoService的工廠類,結果就找到了ReferenceBean<DemoService>

(3)spring會調用ReferenceBean的getObject方法,以獲得一個DemoService實例,ReferenceBean的getObject方法會調用調用ReferenceConfig的createProxy()方法,構建Invoker 實例以及遠程服務的代理對象,然後返回這個對象

(4)然後客戶端就可以通過這個代理對象執行的對遠程服務的調用了

從上面的流程中我們可以看出createProxy()方法是一個關鍵,接下來我們就來看看這個方法執行了什麼操作吧

(1)首先就是我們上面提到的創建Invoker的流程了,主要流程如下所示:

  1. 按照慣例,在進行具體工作之前,需先進行配置檢查與收集工作
  2. 接着根據收集到的信息決定服務引用的方式,有三種:

本地 (JVM) 服務引用、直連方式引用遠程服務、註冊中心引用遠程服務

  1. 不管是哪種引用方式,最後都會得到一個 Invoker 實例
  2. Invoker擁有調用本地或遠程服務的能力(通過組合protocol生成的ExchangeClient對象獲得遠程通信的能力)

 

(2)創建了Invoker之後,ReferenceConfig會調用ProxyFactory類的getProxy()方法,會通過調用Dubbo的Proxy類而不是java的Proxy類,創建一個被動態代理的遠程服務的代理對象(關鍵就在於這個proxy)

(3)客戶端調用代理對象的時候,會被InvokerInvocationHandler動態代理攔截到,InvokerInvocationHandler中的invoke方法會執調用Invoker的invoke()方法

(4)我們知道Invoker擁有調用本地或遠程服務的能力,其實就是如通過在invoke()方法裏面,調用ExchangeClient進行網絡通信

dubbo獲得遠程服務代理對象時序圖:

 

流程其他關鍵點:

(1)Dubbo 服務引用的時機

上面爲了簡化流程我們沒有提到,實際上Dubbo 服務引用的時機有兩個:

  • 第一個是在 Spring 容器調用 ReferenceBean 的 afterPropertiesSet 方法時引用服務(這也是bean的生命週期中的方法,其會在對應bean的所有屬性都初始化完成之後被調用)
  • 第二個是在 ReferenceBean 對應的服務被注入到其他類中時引用(ReferenceBean 實現了FactoryBean,因此會被spring當做一個生產bean的工廠)(依賴注入,並不是在運行的時候,如果是被單例bean引用,在springIOC容器初始化之後,執行以來注入的時候就會被引用)

這兩個引用服務的時機區別在於,第一個是餓漢式的,第二個是懶漢式的。默認情況下,Dubbo 使用懶漢式引用服務。如果需要使用餓漢式,可通過配置 <dubbo:reference> 的 init 屬性開啓

(2)多個註冊中心的invoker

如果有多個註冊中心,此時需要通過集羣管理類 Cluster 將多個 Invoker 合併成一個實例。合併後的 Invoker 實例同樣具備調用本地或遠程服務的能力

(3)動態代理的實現機制

dubbo通過代理工廠類 (ProxyFactory) 爲服務接口生成代理類Proxy,默認是使用Javassist生成的Proxy

Invoker

Invoker 是 Dubbo 的核心模型,代表一個可執行體。在服務提供方,Invoker 用於調用服務提供類。在服務消費方,Invoker 用於執行遠程調用。Invoker 是由 Protocol 實現類構建而來(也就是說或是不同的協議提供不同的Invoker,從中我們可以嗅到什麼味道?我們知道協議不同,底層通信機制不同,Invoker下面應該也有對應的通信機制)

 

果然DubboInvoker中組合了ExchangeClient,但是ExchangeClient其實並不具備通信能力,它需要基於更底層的客戶端實例進行通信。比如 NettyClient、MinaClient 等,默認情況下,Dubbo 使用 NettyClient 進行通信

 

ExchangeClient 客戶端是 Exchangers 的 connect 方法被調用的時候創建的,會通過 SPI 機制加載指定的 HeaderExchangeClient 實例,默認是HeaderExchangeClient,

 

HeaderExchangeClient需要使用底層通信機制就需要,組合dubbo的transport層的對象,假如我們是使用的dubbo協議暴露服務,那麼Transporters就會通過SPI機制返回一個NettyTransporter,在往下就是通過 Netty 提供的 API 構建 Netty 客戶端了

 

Invoker的封裝

  • Invoker 是 Provider 的一個可調用 Service 的抽象, Invoker 封裝了 Provider 地址及 Service 接口信息
  • Directory 維護服務列表,每個服務被封裝成一個 Invoker ,可以把它看成 List<Invoker> ,但與 List 不同的是,它的值可能是動態變化的,比如註冊中心推送變更
  • Cluster 將 Directory 中的多個 Invoker 僞裝成一個 Invoker ,對上層透明,僞裝過程包含了容錯邏輯,調用失敗後,重試另一個
  • Router 負責從多個 Invoker 中按路由規則選出子集,比如讀寫分離,應用隔離等
  • LoadBalance 負責從多個 Invoker 中選出具體的一個用於本次調用,選的過程包含了負載均衡算法,調用失敗後,需要重選

 

 

 

 

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