二. 註冊中心
首先需要說明的一點是,服務的暴露與註冊是兩個不同的概念。在Dubbo中,微服務之間的交互默認是通過Netty進行的,而服務之間的通信是基於TCP以全雙工的方式進行的。那麼也就是說,每個服務都會存在一個ip和port。所謂的服務暴露就是指根據配置將當前服務使用Netty綁定一個本地的端口號(對於消費者而言,則是嘗試連接目標服務的ip和端口)。至於註冊,由於微服務架構中對於新添加的服務,需要一定的機制來通知消費者,有新的服務可用,或者對於某些下線的服務,也需要通知消費者,將這個已經下線的服務給移除。Dubbo中服務的註冊與發現默認是委託給zookeeper來進行的。
服務暴露:書 5.2.2 章,文章《Dubbo服務暴露與註冊》
參考地址:《阿里dubbo服務註冊原理解析》
詳細調用過程:《dubbo服務註冊與發現、服務調用過程》
ServiceBean#afterSetProperties 中調用了 com.alibaba.dubbo.config.ServiceConfig#export
方法,主要代碼如下:
//如果配置不是local則暴露爲遠程服務.(配置爲local,則表示只暴露本地服務)
if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
if (registryURLs != null && registryURLs.size() > 0
&& url.getParameter("register", true)) {
for (URL registryURL : registryURLs) {
url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
Exporter<?> exporter = protocol.export(invoker);
exporters.add(exporter);
}
} else {
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
Exporter<?> exporter = protocol.export(invoker);
exporters.add(exporter);
}
}
整個服務的暴露過程如下圖所示:
然後再補上一消費者調用提供者的圖:
下面給出具體某一種協議的實現,假設配的協議是dubbo,註冊中心用的是zookeepr。那麼代碼的調用過程大致是這樣:
-
調用 JavassistProxyFactory 生成一個Invoker;
-
用com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol#export 方法,進行一個服務的暴露;
-
DubboProtocol#export 方法最終會調用 com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistryFactory#createRegistry;進行一個服務註冊;
這時 zookeeper 相應的目錄下面就會有對應的內容,這時服務註冊就算完成了。
注:本業務組實現的框架中,服務註冊與發現方式見《項目經歷—註冊中心》篇