設計

以ServiceConfig類為起點,主要過程為執(zhí)行invoker和Exporter兩個操作,這樣看起來就清晰了。下面是整個export的時序圖,從中可以看出ServiceConfig動作為createInvoker()和export(),Protocol執(zhí)行了init()和exported()。

注冊中心暴露服務
ServiceConfig 解析出的 URL 的格式為: registry://registry-host/com.alibaba.dubbo.registry.RegistryService?export=URL.encode("dubbo://service-host/com.foo.FooService?version=1.0.0"),
基于擴展點自適應機制,通過 URL 的 registry:// 協(xié)議頭識別,就會調(diào)用 RegistryProtocol 的 export() 方法,將 export 參數(shù)中的提供者 URL,先注冊到注冊中心。
再重新傳給 Protocol 擴展點進行暴露: dubbo://service-host/com.foo.FooService?version=1.0.0,然后基于擴展點自適應機制,通過提供者 URL 的 dubbo:// 協(xié)議頭識別,就會調(diào)用 DubboProtocol 的 export() 方法,打開服務端口。

首先 ServiceConfig 類拿到對外提供服務的實際類 ref(如:HelloWorldImpl),然后通過 ProxyFactory 類的 getInvoker 方法使用 ref 生成一個 AbstractProxyInvoker 實例,到這一步就完成具體服務到 Invoker 的轉(zhuǎn)化。接下來就是 Invoker 轉(zhuǎn)換到 Exporter 的過程。
Dubbo 處理服務暴露的關(guān)鍵就在 Invoker 轉(zhuǎn)換到 Exporter 的過程,上圖中的紅色部分。 Dubbo 和 RMI 這兩種典型協(xié)議的實現(xiàn)如下:
Dubbo 的實現(xiàn)
Dubbo 協(xié)議的 Invoker 轉(zhuǎn)為 Exporter 發(fā)生在 DubboProtocol 類的 export 方法,它主要是打開 socket 偵聽服務,并接收客戶端發(fā)來的各種請求,通訊細節(jié)由 Dubbo 自己實現(xiàn)。RMI 的實現(xiàn)
RMI 協(xié)議的 Invoker 轉(zhuǎn)為 Exporter 發(fā)生在 RmiProtocol類的 export 方法,它通過 Spring 或 Dubbo 或 JDK 來實現(xiàn) RMI 服務,通訊細節(jié)這一塊由 JDK 底層來實現(xiàn),這就省了不少工作量。
暴露過程
初始化的時候掃描配置文件,調(diào)用父類的方法registerBeanDefinitionParser(),存入一個名為parsers的hashMap中。

然后ServiceConfig類中的export方法不知道怎么的就執(zhí)行了到這了,可以看到方法里可以立即加載和延時加載。

在調(diào)用當前類的doExport方法。方法中檢查了加載的參數(shù)完不完整,正不正確。

接下來進入doExportUrls();方法,可以看到這里有個for循環(huán),可以接受多個注冊地址。

然后進入doExportUrlsFor1Protocol()方法,這個方法比較長,前半段負責檢查拼裝參數(shù),還有一些邏輯,我覺得最重要的是下面箭頭所指的兩行代碼,第一個是通過代理工廠生成代理方法,第二個是暴露服務。

第二個會進入ProtocolFilterWrapper的export方法,調(diào)用buildInvokerChain鏈

會默認進入DubboProtocol里,在這里的調(diào)用openServer()

仔細看看openServer()都干了啥,openServer調(diào)用createServer(url),createServer(url)中最重要的bind方法。

一步一步走下去,看到是調(diào)用了Transporters的bind方法。

點進去bind方法,可以看到getTransporter()這個方法返回了一個Transporter對象,看一下Transporter的接口,bind方法上有@Adaptive注解,在 Dubbo 的 ExtensionLoader 的擴展點類對應的 Adaptive 實現(xiàn)是在加載擴展點里動態(tài)生成。指定提取的 URL 的 Key 通過 @Adaptive 注解在接口方法上提供。對于 bind() 方法,Adaptive 實現(xiàn)先查找 server key,如果該 Key 沒有值則找 transport key 值,來決定代理到哪個實際擴展點。默認使用SPI中設定的值,所以是netty。



在NettyServer繼承了AbstractServer并且實現(xiàn)了Server接口,可以看到NettyServer在構(gòu)造方法中實現(xiàn)了父類的構(gòu)造方法,調(diào)用了doOpen,也可以看到打出start bind export的日志。



然后進入到RegistryProtocol的export方法,在這里注冊服務到zookeeper

調(diào)用下面方法,設置協(xié)議等

執(zhí)行這句 final Registry registry = getRegistry(originInvoker);

調(diào)用AbstractRegistryFactory的getRegistry

ZookeeperRegistryFactory的createRegistry的方法,因為ZookeeperRegistryFactory繼承了AbstractRegistryFactory,AbstractRegistryFactory實現(xiàn)了RegistryFactory接口,而這個接口的getRegistry方法注解為@Adaptive({"protocol"}),之前有設置協(xié)議為zookeeper,所以根據(jù)名稱選擇了ZookeeperRegistryFactory的實現(xiàn)。

這里調(diào)用zookeeperTransporter的connect,就跟調(diào)用netty一樣的

默認Zkclient的實現(xiàn)

在這里創(chuàng)建連接

創(chuàng)建成功之后,dubbo自己存一份

然后返回RegistryProtocol的export方法,添加一些訂閱監(jiān)聽
最后回到ServiceConfig的export方法,整個服務暴露完成。
參考:http://dubbo.io/books/dubbo-dev-book/design.html
各位大神多多指導