在上一篇文章 Dubbo之服務暴露分析 中介紹了當遠程暴露時,如果有註冊中心,需要在服務暴露後再將服務註冊到註冊中心。該篇將介紹該功能的有關步驟。 註冊的起點 在 方法包含了服務導出,註冊,以及數據訂閱等邏輯。其中服務註冊先調用 方法。 可以看出,服務註冊主要包括兩部分, 獲取註冊中心實例 和 向註 ...
在上一篇文章Dubbo之服務暴露分析中介紹了當遠程暴露時,如果有註冊中心,需要在服務暴露後再將服務註冊到註冊中心。該篇將介紹該功能的有關步驟。
註冊的起點
在RegistryProtocol.export()
方法包含了服務導出,註冊,以及數據訂閱等邏輯。其中服務註冊先調用RegistryProtocol.register()
方法。
public void register(URL registryUrl, URL registeredProviderUrl) {
// 獲取 Registry
Registry registry = registryFactory.getRegistry(registryUrl);
// 註冊服務
registry.register(registeredProviderUrl);
}
可以看出,服務註冊主要包括兩部分,獲取註冊中心實例和向註冊中心註冊服務。
獲取註冊中心實例
(1)調用registryFactory.getRegistry(registryUrl)
方法,它會先訪問緩存,緩存中不存在則調用createRegistry(URL)
方法創建Registry,然後寫入緩存。這裡的createRegistry是一個模版方法,有具體的子類實現。這裡假設使用zookeeper作為註冊中心,則調用ZookeeperRegistryFactory的createRegistry()方法。
public Registry createRegistry(URL url) {
// 創建 ZookeeperRegistry
return new ZookeeperRegistry(url, zookeeperTransporter);
}
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
super(url);
if (url.isAnyHost()) {
throw new IllegalStateException("registry address == null");
}
// 獲取組名,預設為 dubbo
String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
if (!group.startsWith(Constants.PATH_SEPARATOR)) {
// group = "/" + group
group = Constants.PATH_SEPARATOR + group;
}
this.root = group;
// 創建 Zookeeper 客戶端,預設為 CuratorZookeeperTransporter
zkClient = zookeeperTransporter.connect(url);
// 添加狀態監聽器
zkClient.addStateListener(new StateListener() {
@Override
public void stateChanged(int state) {
if (state == RECONNECTED) {
try {
recover();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
});
}
(2) 在ZookeeperRegistry
構造方法中調用connect(url)
方法,預設是CuratorZookeeperClient
, 獲得一個ZkClient客戶端,之後添加狀態監聽器。
向註冊中心註冊服務
假設存在一個服務com.alibaba.dubbo.demo.DemoService, 那麼 這個服務對應的配置信息(存儲在 URL 中)最終被註冊到了 /dubbo/com.alibaba.dubbo.demo.DemoService/providers/ 節點下。
(1) 調用FailbackRegistry.register()
方法,之後調用裡面的doRegister
方法,它是一個模版方法,在ZookeeperRegistry
中實現。
protected void doRegister(URL url) {
try {
// 通過 Zookeeper 客戶端創建節點,節點路徑由 toUrlPath 方法生成,路徑格式如下:
// /${group}/${serviceInterface}/providers/${url}
zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
} catch (Throwable e) {
throw new RpcException("Failed to register...");
}
}
(2) 調用create()
方法。通過遞歸創建當前節點的上一級路徑,然後再根據ephemeral的值決定是創建臨時還是持久節點。分別調用createEphemeral
和createPersistent
方法。