1. 程式人生 > >Dubbo系列之 (五)服務訂閱(2)

Dubbo系列之 (五)服務訂閱(2)

# 輔助連結 ## [Dubbo系列之 (一)SPI擴充套件 ](https://www.cnblogs.com/liferecord/p/13445631.html) ## [Dubbo系列之 (二)Registry註冊中心-註冊(1)](https://www.cnblogs.com/liferecord/p/13462175.html) ## [Dubbo系列之 (三)Registry註冊中心-註冊(2)](https://www.cnblogs.com/liferecord/p/13497411.html) ## [Dubbo系列之 (四)服務訂閱(1)](https://www.cnblogs.com/liferecord/p/13524747.html) ## [Dubbo系列之 (五)服務訂閱(2)](https://www.cnblogs.com/liferecord/p/13540399.html) # 服務訂閱,閱讀程式碼前的一些思考? 思考的過程和設計思想如下: 1、我們想要進行遠端服務的呼叫,那麼肯定要建立網路連線,不妨改用TCP長連線,並設計通訊協議,並封裝為一個類,不妨叫做ExchangeClient。用它來進行網路通訊。 2、有了可以進行遠端通訊的服務物件ExchangeClient後,我們可以把遠端服務封裝為一個Invoker物件,這個Invoker物件內部採用自已定義的協議與遠端伺服器通訊,不妨叫做DubboInvoker,因為採用了dubbo協議來進行網路通訊的。 3、有了這個DubboInvoker 我就可以根據dubbo協議與遠端服務通訊了,但是我還想在本地增加一些過濾器Filter,或者監聽器Listener。沒關係,直接通過責任鏈模式,把這些Filter與這個DubboInvoker進行連結。返回的一個ProtocolFilterWrapper物件。 4、同理,如果需要一些監聽器的功能怎麼辦,同樣進行一次封裝。把ProtocolFilterWraper封裝到Listener型別的Invoker物件,不妨叫做ListenerInvokerWrapper。 5、現在考慮遠端服務提供者有很多個,那麼我對每個遠端服務都需要有一個ListenerInvokerWrapper的物件。如下: Demoservice::196.254.324.1 ListenerInvokerWrapper1 Demoservice::196.254.324.2 ListenerInvokerWrapper2 Demoservice::196.254.324.3 ListenerInvokerWrapper3 Demoservice::196.254.324.4 ListenerInvokerWrapper4 Demoservice::196.254.324.5 ListenerInvokerWrapper5 ..... 6、服務太多了,在本地這樣建立太費事了。引入了註冊中心,直接把服務註冊到服務中心上,然後客戶端直接從註冊中心拉取。我們把拉取到的服務,統稱為服務目錄。並且它是從註冊中心拉取到的,那麼不妨名字就叫做RegistryDirectory。那麼這個服務目錄裡肯定包含了上面的遠端服務呼叫物件ListenerInvokerWrapper。我們把這些物件放到服務目錄的成員上,名字就叫做urlInvokerMap。key: Demoservice::xxxx。value:ListenerInvokerWrapper。 7、現在我們可以在本地呼叫RegistryDirectory物件,與遠端服務通訊了,想調哪個服務就從urlInvokerMap取出一個進行呼叫即可。但是每次指定一個遠端伺服器,不僅太麻煩了,而且也會造成流量不均勻,負載不平衡。那麼我們就通過通過負載均衡策略來選擇一個服務呼叫。就取名LoadBalance吧。他有個方法select。入參就是我們的服務目錄RegistryDirectory。那麼通過LoadBalance.select(RegistryDirectory) 得到一個我們想要的通訊的遠端服務即可。目前負載均衡演算法有一致性Hash演算法,隨機演算法、權重輪訓演算法、最短響應時間演算法、最少活躍數演算法。 8、有了負載均衡演算法LoadBalance後,我想要這樣的功能,當服務呼叫失敗的時候,我可以重試,或者直接直接失敗。那我就把有這種能力服務呼叫,稱為一個叢集Cluster。他有一個方法叫做join。入參還是服務目錄RegistryDirectory。返回一個具有快速失敗、或者重試的服務呼叫,不妨叫AbstractClusterInvoker。每個不同的策略都去實現它。並且這個物件內部通過LoadBalance來選擇一個服務進行呼叫,失敗後的策略(是否重試或失敗)由我決定。 9、目前我們已經有了一個XXXclusterInvoker 物件,它具有快速失敗或者重試等功能,且具有負載均衡演算法的遠端服務呼叫物件。但是有時,這些遠端服務提供者這的qps不達標,或者新上線的服務有問題,或者遠端服務呼叫失敗後,可以在本地模擬的呼叫,返回一個mock物件。那麼我們重新對XXXclusterInvoker進行封裝,就命名為MockClusterInvoker,具有Mock功能,且具有叢集能力。它持有我們的服務目錄RegistryDirectory和XXXclusterInvoker物件。 10、目前我們已經有了一個MockClusterInvoker物件。但是這個invoker物件和我們像本地一樣呼叫服務還是有點差別,最後我們直接通過Java的動態代理計算Proxy.newInstance()來建立一個具體的服務物件DemoService,並且在InvokeHandler內部呼叫我們的MockClusterInvoker物件的invoke 方法。 11、比如我們的DubboInvoker是通過Java 非同步執行緒CompletableFuture實現的話,如果需要轉為同步,還可以對其封裝從非同步轉為同步的Invoker,不妨命名為AsyncToSyncInvoker。 則最終在服務消費端呈現給我們如下一個遠端服務代理物件。 ![](https://img2020.cnblogs.com/blog/672564/202008/672564-20200821123910873-649847882.png) #ReferenceBean#getObject() 在上一章節,已經說明了getObject()物件的呼叫時機,內部呼叫的ReferenceConfig#init方法,該init()方法主要做了如下幾件事情: 1、預設的配置進行填充,比如registry,application等屬性。 2、校驗配置是否填寫正確