1. 程式人生 > >Dubbo原始碼分析:Register註冊中心

Dubbo原始碼分析:Register註冊中心

Registry

每個註冊中心對應一個Registry例項,包括dubbo,zookeeper,redis, multicast。
(1)Set型別的registed:記錄provider註冊過的service url。
(2)ConcurrentMap<URL, Set> subscribed:consumer訂閱URL,URL有變化時的監聽器NotifyListener;其中多個NotifyListener是因為consumer存在多個地方呼叫這個service,NotifyListener的實現為RegistryDirectory。
(3)ConcurrentMap<URL, Map<String, List>> notified:key為消費者url, value為服務提供者url列表。儲存消費者consumerURL對應提供者providerURL列表,之後真正進行服務呼叫的時候,直接從notified列表取出providerURL即可。
(4)file與properties:consumer將從註冊中心獲取的provider urls儲存到本地file,同時載入到properties,避免註冊中心掛了,此時consumer還可以連線provider。

RegistryFactory

工廠類,負責生成Registry例項,維護Registry例項快取,根據底層實現技術的不同,分為dubbo,zookeeper,redis,multicast實現。

RegistryProtocol:註冊協議

  1. export方法:負責將provider的service註冊到註冊中心,具體呼叫了在ServiceConfig中通過ExtensionLoader載入RegistryProtocol。
  2. 註冊中心實現選擇:包括:zookeeper,redis,dubbo。確定RegistoryFactory的實現:一旦RegistoryFactory實現確定,則Registry就確定了。
  • 根據ExtensionLoader的分析,通過ServiceConfig確定採用的是RegistryProtocol,通過RegistryProtocol的export方法註冊service到註冊中心。
  • RegistryProtocol通過ExtensionLoader確定RegistryFactory的實現類。
  1. 具體過程
    (1)在RegistryProtocol的export方法呼叫了getReigstry(originInvoker):
    在這裡插入圖片描述
    如下:右下角為originInvoker的url的protocol和相關parameters,registry -> zookeeper,所以通過setProtocol設定值為zookeeper,故最終選擇的是ZookeeperRegistoryFactory,具體看(2)中RegistryFactory的SPI和@Adaptive規則。
    在這裡插入圖片描述

    getRegistry的實現:模板設計模式,最終由具體實現類實現createRegistry。
    在這裡插入圖片描述
    ZookeeperRegistry的定義:
    在這裡插入圖片描述

(2)RegistryProtocol中registryFactory實現的確定過程
在獲取registryProtocol例項時,呼叫的getAdaptiveExtension的實現,然後底層繼續呼叫createAdaptiveExtension方法。createAdaptiveExtension再呼叫injectExtension方法,給通過getAdaptiveExtensionClass().newInstance()獲取到的RegistryProtocol例項,注入屬性值,這個功能類似於spring ioc的實現,RegistryProtocol例項包含setRegistoryFactory方法:
在這裡插入圖片描述
在這裡插入圖片描述
如上圖:其中pt為RegistroyFactory,property為registoryFactory,通過objectFactory.getExtension(pt, property)獲取到registoryFactory實現類的例項。objectFactory為SpiExtensionFactory的例項,底層呼叫getExtension:其中type為RegistryFactory。
在這裡插入圖片描述
如下圖:RegistoryFactory介面的@SPI註解,value預設為dubbo,表示預設為DubboRegistryFactory
方法getRegistry為使用@Adaptive({“protocol”}),protocol表示呼叫這個方法的時候,根據URL的protocol對應的值或決定使用哪個RegistryFactory介面實現,由(1)分析protocol為zookeeper。
在這裡插入圖片描述
繼續debug原始碼,查詢loader.getAdaptiveExtension()最終獲取到哪個RegistryFactory實現。最終進入ExtensionLoader的createAdaptiveExtensionClassCode方法,生成的程式碼如下:
在這裡插入圖片描述
即:首先根據呼叫方法getRegistry(URL url),url的protocol選擇RegistryFactory,如果protocol為null,則使用defaultExtName,預設為dubbo。而由(1)分析可知:url的protocol為zookeeper,故最終呼叫的為ZookeeperRegistryFactory。
在這裡插入圖片描述
動態生成的程式碼如下:

package com.alibaba.dubbo.registry;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class RegistryFactory$Adpative implements com.alibaba.dubbo.registry.RegistryFactory {
	public com.alibaba.dubbo.registry.Registry getRegistry(com.alibaba.dubbo.common.URL arg0) {
		if (arg0 == null) throw new IllegalArgumentException("url == null");
		com.alibaba.dubbo.common.URL url = arg0;
		String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
		if(extName == null) 
			throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.registry.RegistryFactory) name from url(" + url.toString() + ") use keys([protocol])");
		com.alibaba.dubbo.registry.RegistryFactory extension = (com.alibaba.dubbo.registry.RegistryFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.registry.RegistryFactory.class).getExtension(extName);
		return extension.getRegistry(arg0);
	}
}

RegistryDirectory:消費者訂閱監聽器