請支持原創:
http://www.cnblogs.com/donlianli/p/3847676.html
作者當前分析的版本為2.5.x。作者在分析的時候,都是帶着疑問去查看代碼,debug進行調試的,筆者寫此文章僅供參考。
先大概了解一下系統作為一個消費者從啟動到注冊完成的過程
- 系統啟動時,引用service時首先將系統本身自己需要引用的服務注冊到zookeeper,然后訂閱系統需要的服務,最后,會接收到zookeeper發送的訂閱信息。比如一個消費者注冊了一個UserService,系統在啟動時,首先聲明自己是UserService的一個消費者,然后再向zookeeper聲明自己需要訂閱UserService,最后,從zookeeper接收訂閱的服務,然后存儲到本地。
- 如果同時引用多個接口,則上面的服務會重復執行多次。
- montitorService是在執行的時候,才執行訂閱。
問題:
1、dubbo是通過哪個類跟zookeeper進行交互的?
2、dubbo把訂閱的信息存儲到了哪個類?
RegistryProtocol.doRefer這里面進行的注冊,將調用FailbackRegistry.registry進行真正的注冊,實際跟zookeeper進行交互,調用的是ZookeeperRegistry的doRegistry方法。如果注冊失敗,會將url添加定定時任務中進行重試。
AbstractRegistry.notify真正接收到zookeeper的通知。在那兒將notify接口添加到zookeeper的改變事件的呢?
在ZookeeperRegistry代碼的doSubscribe方法中(與zookeeper進行交互的代碼中),將訂閱的接口發送給zookeeper,並且從zookeeper取得可用的服務列表。
ZookeeperRegistry代碼:
zkClient.create(path, false); //這個是zookeeper返回客戶端訂閱的服務 List<String> children = zkClient.addChildListener(path, zkListener); if (children != null) { urls.addAll(toUrlsWithEmpty(url, path, children)); } 在循環之外,將已經可用的列表進行通知。 notify(url, listener, urls);,調用了AbstractRegistry.notify
AbstractRegistry在收到通知后,將url進行存儲,繼續通知NotifyListener。
NotifyListener是在哪兒放入Registry的呢?
在RegistryProtocol訂閱服務的時候,會調用RegistryDirectory.subscribe方法。RegistryDirectory這類本身就實現了NotifyListener接口,在調用FailbackRegistry的subscribe方法的時候,把自己當成一個參數傳遞給了AbstractRegistry對象。所以AbstractRegistry在收到通知后,繼續通知的是RegistryDirectory。
RegistryDirectory這個類維護着從本地方法到遠程方法的映射關系,遠程參數到本地方法的調用關系等。
在注冊過程中的幾個主要類
ZookeeperRegistry:負責與zookeeper進行交互
RegistryProtocol:從注冊中心獲取可用服務,或者將服務注冊到zookeeper,然后提供服務或者提供調用代理。
RegistryDirectory:維護着所有可用的遠程Invoker或者本地的Invoker。這個類實現了NotifyListner。
NotifyListener:負責RegistryDirectory和ZookeeperRegistry的通信。
FailbackRegistry:繼承自Registry,實現了失敗重試機制。
回答一開始的問題
1、通過
ZookeeperRegistry和Zookeeper進行交互,相關的類還有ZookeeperClient,ZkclientZookeeperClient和org.I0Itec.zkclient.ZkClient類。通過這些類的方法,實現服務的注冊和訂閱及信息的傳遞。
2、主要是AbstractRegistry和RegistryDirectory這兩個類。其中RegistryDirectory存儲的可供客戶端直接調用的Invoker,而AbstractRegistry這個類主要存儲的是已經注冊的服務接口,已經訂閱的服務接口和已經收到通知的接口的URL,不能直接調用。