dubbo服務註冊流程

服務註冊流程

RegistryProtocol

dubbo服務發佈流程已經分析了發佈服務流程還有服務註冊流程

export

RegistryProtocol#export繼續服務註冊流程

  // 根據invoker中的url獲取Registry實例: zookeeperRegistry
  // ListenerRegistryWrapper(ZookeeperRegistry) 後面註冊服務闡述
  final Registry registry = getRegistry(originInvoker);
  // 獲取要註冊的到註冊中心的URL: dubbo://ip:port
  final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
  // decide if we need to delay publish
  boolean register = providerUrl.getParameter(REGISTER_KEY, true);
  // 是否配置了註冊中心,如果是,則需要註冊
  if (register) {
  	// 將ProviderURL註冊到註冊中心
      register(registryUrl, registeredProviderUrl);
  }

getRegistry

 protected Registry getRegistry(final Invoker<?> originInvoker) { 
 		// 把 url 轉化爲對應配置的註冊中心的具體協議 如:zookeeper://ip:port 
       URL registryUrl = getRegistryUrl(originInvoker);
       // 根據具體協議從registryFactory獲取指定的註冊中心實現 ZookeeperRegistry
       return registryFactory.getRegistry(registryUrl);
   }

RegistryProtocol#register

    public void register(URL registryUrl, URL registeredProviderUrl) {  
    	// registryFactory是一個擴展點RegistryFactory$Adaptive
    	// 並且這個擴展點有一個包裝類 RegistryFactoryWrapper 
    	// 最終獲取的的registryFactory是RegistryFactoryWrapper(ZookeeperRegistryFactory)
    	// 這裏獲得的registry的是 ListenerRegistryWrapper(ZookeeperRegistry)
        Registry registry = registryFactory.getRegistry(registryUrl);
        registry.register(registeredProviderUrl);

        ProviderModel model = ApplicationModel.getProviderModel(registeredProviderUrl.getServiceKey());
        model.addStatedUrl(new ProviderModel.RegisterStatedURL(
                registeredProviderUrl,
                registryUrl,
                true
        ));
    }

RegistryFactory

方法級別自適應擴展點在RegistryProtocol 通過set依賴注入

@SPI("dubbo")
public interface RegistryFactory {
    @Adaptive({"protocol"})
    Registry getRegistry(URL url);
}

RegistryFactory擴展點的配置文件META-INF\dubbo\internal\org.apache.dubbo.registry.RegistryFactory

service-discovery-registry=org.apache.dubbo.registry.client.ServiceDiscoveryRegistryFactory
wrapper=org.apache.dubbo.registry.RegistryFactoryWrapper
dubbo=org.apache.dubbo.registry.dubbo.DubboRegistryFactory
multicast=org.apache.dubbo.registry.multicast.MulticastRegistryFactory
zookeeper=org.apache.dubbo.registry.zookeeper.ZookeeperRegistryFactory
redis=org.apache.dubbo.registry.redis.RedisRegistryFactory
consul=org.apache.dubbo.registry.consul.ConsulRegistryFactory

etcd3=org.apache.dubbo.registry.etcd.EtcdRegistryFactory
nacos=org.apache.dubbo.registry.nacos.NacosRegistryFactory
sofa=org.apache.dubbo.registry.sofa.SofaRegistryFactory
multiple=org.apache.dubbo.registry.multiple.MultipleRegistryFactory

RegistryFactory$Adaptive

public class RegistryFactory$Adaptive implements org.apache.dubbo.registry.RegistryFactory {
    public org.apache.dubbo.registry.Registry getRegistry(org.apache.dubbo.common.URL arg0)  {
        if (arg0 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg0;
        // extName -> zookeeper
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.registry.RegistryFactory) name from url (" + url.toString() + ") use keys([protocol])");
        // 返回的RegistryFactory是RegistryFactoryWrapper(ZookeeperRegistryFactory)
        org.apache.dubbo.registry.RegistryFactory extension = (org.apache.dubbo.registry.RegistryFactory)ExtensionLoader.getExtensionLoader(org.apache.dubbo.registry.RegistryFactory.class).getExtension(extName);
        return extension.getRegistry(arg0);
    }
}

RegistryFactoryWrapper

可以看到RegistryFactory的擴展點配置文件中有wrapper=org.apache.dubbo.registry.RegistryFactoryWrapper
所有RegistryFactory$Adaptive#getRegistry方法中獲取的RegistryFactory是用RegistryFactoryWrapper增強的ZookeeperRegistryFactory

public class RegistryFactoryWrapper implements RegistryFactory {
    private RegistryFactory registryFactory;
    public RegistryFactoryWrapper(RegistryFactory registryFactory) {
        this.registryFactory = registryFactory;
    }

    @Override
    public Registry getRegistry(URL url) {
        return new ListenerRegistryWrapper(registryFactory.getRegistry(url),
                Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(RegistryServiceListener.class)
                        .getActivateExtension(url, "registry.listeners")));
    }
}

ZookeeperRegistryFactory

getRegistry

ZookeeperRegistryFactory中沒有看到getRegistry 所有調用其父類AbstractRegistryFactory的getRegistry方法

public class ZookeeperRegistryFactory extends AbstractRegistryFactory {

    private ZookeeperTransporter zookeeperTransporter;
    /**
     * Invisible injection of zookeeper client via IOC/SPI
     * @param zookeeperTransporter
     */
    public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) {
        this.zookeeperTransporter = zookeeperTransporter;
    }
    @Override
    public Registry createRegistry(URL url) {
        return new ZookeeperRegistry(url, zookeeperTransporter);
    }

}

AbstractRegistryFactory.getRegistry

  public Registry getRegistry(URL url) {
        if (destroyed.get()) {
            LOGGER.warn("All registry instances have been destroyed, failed to fetch any instance. " +
                    "Usually, this means no need to try to do unnecessary redundant resource clearance, all registries has been taken care of.");
            return DEFAULT_NOP_REGISTRY;
        }
        // 獲取url
        url = URLBuilder.from(url)
                .setPath(RegistryService.class.getName())
                .addParameter(INTERFACE_KEY, RegistryService.class.getName())
                .removeParameters(EXPORT_KEY, REFER_KEY)
                .build();
        String key = url.toServiceStringWithoutResolving();
        // Lock the registry access process to ensure a single instance of the registry
        LOCK.lock();
        try {
        	// 從緩存中獲取Register 
            Registry registry = REGISTRIES.get(key);
            if (registry != null) {
                return registry;
            }
            //create registry by spi/ioc 
            // 創建registry
            registry = createRegistry(url); // 這是一個模板方法,有子類實現如ZookeeperRegistryFactory.createRegistry
            if (registry == null) {
                throw new IllegalStateException("Can not create registry " + url);
            }
            REGISTRIES.put(key, registry);
            return registry;
        } finally {
            // Release the lock
            LOCK.unlock();
        }
    }

createRegistry

ZookeeperRegistryFactory#createRegistry

 @Override
    public Registry createRegistry(URL url) {
        return new ZookeeperRegistry(url, zookeeperTransporter);
    }

通過上面的方法最終得到的registry是ListenerRegistryWrapper(ZookeeperRegistry)

ZookeeperRegistry

ZookeeperRegistry構造函數
這個方法中使用了 CuratorZookeeperTransport 來實現 zk 的連接

public class ZookeeperRegistry extends FailbackRegistry {
    private final static Logger logger = LoggerFactory.getLogger(ZookeeperRegistry.class);
    private final static String DEFAULT_ROOT = "dubbo";
    private final String root;
    private final Set<String> anyServices = new ConcurrentHashSet<>();
    private final ConcurrentMap<URL, ConcurrentMap<NotifyListener, ChildListener>> zkListeners = new ConcurrentHashMap<>();
    private final ZookeeperClient zkClient;
    public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
        super(url);
        if (url.isAnyHost()) {
            throw new IllegalStateException("registry address == null");
        }
        // 獲得group名稱
        String group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);
        if (!group.startsWith(PATH_SEPARATOR)) {
            group = PATH_SEPARATOR + group;
        }
        this.root = group;
        // ZookeeperTransporter是一個擴展點 基於方法適配 默認使用curator實現
        // 產生一個zookeeper連接
        zkClient = zookeeperTransporter.connect(url);
        // 添加zookeeper狀態變化事件
        zkClient.addStateListener((state) -> {
            if (state == StateListener.RECONNECTED) {
                logger.warn("Trying to fetch the latest urls, in case there're provider changes during connection loss.\n" +
                        " Since ephemeral ZNode will not get deleted for a connection lose, " +
                        "there's no need to re-register url of this instance.");
                ZookeeperRegistry.this.fetchLatestAddresses();
            } else if (state == StateListener.NEW_SESSION_CREATED) {
                logger.warn("Trying to re-register urls and re-subscribe listeners of this instance to registry...");
                try {
                    ZookeeperRegistry.this.recover();
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            } else if (state == StateListener.SESSION_LOST) {
                logger.warn("Url of this instance will be deleted from registry soon. " +
                        "Dubbo client will try to re-register once a new session is created.");
            } else if (state == StateListener.SUSPENDED) {

            } else if (state == StateListener.CONNECTED) {

            }
        });
    }

registry.register(registedProviderUrl)

繼續往下分析,會調用 registry.register 去將 dubbo://的協議地址註冊到 zookeeper 上
ZookeeperRegistry 這個類中並沒有 register 這個方法,但是他的父類 FailbackRegistry 中存在 register 方法,而這個類又重寫了 AbstractRegistry 類中的 register 方法。所以我們可以直接定位到 FailbackRegistry 這個類中的 register 方法中

FailbackRegistry.register

  • FailbackRegistry,從名字上來看,是一個失敗重試機制
  • 調用父類的 register 方法,講當前 url 添加到緩存集合中
   public void register(URL url) {
        if (!acceptable(url)) {
            logger.info("URL " + url + " will not be registered to Registry. Registry " + url + " does not accept service of this protocol type.");
            return;
        }
        super.register(url);
        removeFailedRegistered(url);
        removeFailedUnregistered(url);
        try {
            // 調用子類實現真正的服務註冊,把 url 註冊到 zk 上
            doRegister(url);
        } catch (Exception e) { // 失敗重試
            Throwable t = e;
            // If the startup detection is opened, the Exception is thrown directly.
            // 如果開啓了啓動時檢測,則直接拋出異常
            boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)
                    && url.getParameter(Constants.CHECK_KEY, true)
                    && !CONSUMER_PROTOCOL.equals(url.getProtocol());
            boolean skipFailback = t instanceof SkipFailbackWrapperException;
            if (check || skipFailback) {
                if (skipFailback) {
                    t = t.getCause();
                }
                throw new IllegalStateException("Failed to register " + url + " to registry " + getUrl().getAddress() + ", cause: " + t.getMessage(), t);
            } else {
                logger.error("Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(), t);
            }

            // 將失敗的註冊請求記錄到失敗列表,定時重試
            addFailedRegistered(url);
        }
    }

ZookeeperRegistry.doRegister

最終調用 curator 的客戶端把服務地址註冊到 zk

public void doRegister(URL url) {
        try { 
        	// 這個zkClient 是CuratorZookeeperClient 也是基於擴展點機制實現的
            zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true));
        } catch (Throwable e) {
            throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
   }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章