Dubbo发布过程中,注册中心注册服务

服务的注册时机

在serviceConfig的doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs)方法中,根据协议配置和注册中心地址进行接口服务的发布,在方法执行过程中,根据URL的协议配置进行不同扩展点的加载:
如传入的参数值registryURLs如以下截图:

registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=user-provider&dubbo=2.6.2&pid=4160&registry=zookeeper&timeout=7200&timestamp=1642062386499

方法中构建的url值为:

dubbo://192.168.137.210:20881/com.bail.user.service.IUserService?anyhost=true&application=user-provider&bind.ip=192.168.137.210&bind.port=20881&dubbo=2.6.2&generic=false&getUserById.retries=3&getUserById.timeout=3000&interface=com.bail.user.service.IUserService&methods=getUserById,queryList&pid=4160&retries=2&revision=1.0.0&side=provider&timeout=8000&timestamp=1642062386501&version=1.0.0

在发布本地服务exportLocal(URL url)的过程中,替换了协议的值:

injvm://127.0.0.1/com.bail.user.service.IUserService?anyhost=true&application=user-provider&bind.ip=192.168.137.210&bind.port=20881&dubbo=2.6.2&generic=false&getUserById.retries=3&getUserById.timeout=3000&interface=com.bail.user.service.IUserService&methods=getUserById,queryList&pid=4160&retries=2&revision=1.0.0&side=provider&timeout=8000&timestamp=1642062386501&version=1.0.0

然后根据注册中心url获取invoker,在调用proxyFactory.getInvoker方法时,对registryURL添加了export参数,将 要发布的服务协议地址拼接在了原注册地址后面

registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=user-provider&dubbo=2.6.2&export=dubbo://192.168.137.210:20881/com.bail.user.service.IUserService?anyhost=true&application=user-provider&bind.ip=192.168.137.210&bind.port=20881&dubbo=2.6.2&generic=false&getUserById.retries=3&getUserById.timeout=3000&interface=com.bail.user.service.IUserService&methods=getUserById,queryList&pid=10260&retries=2&revision=1.0.0&side=provider&timeout=8000&timestamp=1642064675763&version=1.0.0&pid=10260&registry=zookeeper&timeout=7200&timestamp=1642064675754

然后调用自适应扩展点的export方法:Exporter<?> exporter = protocol.export(wrapperInvoker),此时wrapperInvoker的Url为registryURL,所以获得的Protocol实际类为:RegistryProtocol。

RegistryProtocol暴露服务

export方法中,首先调用了doLocalExport方法,在本地暴露服务,
然后调用getRegistryUrl方法,获取registryUrl ,供后面放入集合使用。

zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=user-provider&dubbo=2.6.2&export=dubbo://192.168.137.210:20881/com.bail.user.service.IUserService?anyhost=true&application=user-provider&bind.ip=192.168.137.210&bind.port=20881&dubbo=2.6.2&generic=false&getUserById.retries=3&getUserById.timeout=3000&interface=com.bail.user.service.IUserService&methods=getUserById,queryList&pid=10260&retries=2&revision=1.0.0&side=provider&timeout=8000&timestamp=1642064675763&version=1.0.0&pid=10260&timeout=7200&timestamp=1642064675754

随后调用getRegistry方法获取一个注册者registry ,此时的registry 包含一下属性:

随后调用getRegistedProviderUrl方法获取注册服务提供者URL,即服务提供者信息

调用ProviderConsumerRegTable.registerProvider方法进行一个服务提供者的注册表注册,
添加缓存后,则进行服务提供者的注册,调用register(registryUrl, registedProviderUrl)方法根据注册地址和服务接口地址进行注册,方法内部实际调用ZookeeperRegistry的register方法进行服务节点注册;
服务节点注册成功后,调用了ProviderConsumerRegTable的setReg方法,进行providerInvker注册状态更新,设置为true.
然后根据registedProviderUrl注册的提供者URL获取当前url订阅覆盖的url

provider://192.168.31.199:20881/com.bail.user.service.IUserService?anyhost=true&application=user-provider&category=configurators&check=false&dubbo=2.6.2&generic=false&getUserById.retries=3&getUserById.timeout=3000&interface=com.bail.user.service.IUserService&methods=getUserById,queryList&pid=1708&retries=2&revision=1.0.0&side=provider&timeout=8000&timestamp=1642089143813&version=1.0.0

随后根据overrideSubscribeUrl, originInvoker两个参数构建一个OverrideListener,随后根据overrideSubscribeUrl和OverrideListener添加到overrideListeners 缓存中;
然后调用ZookeeperRegistry的subscribe方法进行订阅和通知,最后返回一个DestroyableExporter对象

public class RegistryProtocol implements Protocol {

    private final Map<URL, NotifyListener> overrideListeners = new ConcurrentHashMap<URL, NotifyListener>();
    public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        //export invoker
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);

        URL registryUrl = getRegistryUrl(originInvoker);

        //registry provider
        final Registry registry = getRegistry(originInvoker);
        final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);

        //to judge to delay publish whether or not 判断是否要推迟公布
        boolean register = registedProviderUrl.getParameter("register", true);

        ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);

        if (register) {
            register(registryUrl, registedProviderUrl);
            ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
        }

        // Subscribe the override data
        // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call the same service. Because the subscribed is cached key with the name of the service, it causes the subscription information to cover.
        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
        //Ensure that a new exporter instance is returned every time export
        return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl);
    }

    private URL getProviderUrl(final Invoker<?> origininvoker) {
        String export = origininvoker.getUrl().getParameterAndDecoded(Constants.EXPORT_KEY);
        if (export == null || export.length() == 0) {
            throw new IllegalArgumentException("The registry export url is null! registry: " + origininvoker.getUrl());
        }

        URL providerUrl = URL.valueOf(export);
        return providerUrl;
    }

    public void register(URL registryUrl, URL registedProviderUrl) {
        // 首先根据registryUrl获取注册者,此处调用的是ZookeeperRegistryFactory的getRegistry方法,从AbstractRegistryFactory的缓存REGISTRIES中获取registry 
        Registry registry = registryFactory.getRegistry(registryUrl);
        // 然后调用ZookeeperRegistry的register方法进行服务节点注册
        registry.register(registedProviderUrl);
    }



}

doLocalExport

getCacheKey方法获取的key是provider的值

dubbo://192.168.137.210:20881/com.bail.user.service.IUserService?anyhost=true&application=user-provider&bind.ip=192.168.137.210&bind.port=20881&dubbo=2.6.2&generic=false&getUserById.retries=3&getUserById.timeout=3000&interface=com.bail.user.service.IUserService&methods=getUserById,queryList&pid=10260&retries=2&revision=1.0.0&side=provider&timeout=8000&timestamp=1642064675763&version=1.0.0

然后根据key从绑定缓存中获取ExporterChangeableWrapper对象,如果为空,则new一个新对象,根据创建的invokerDelegete,继续调用protocol的export方法,此时invokerDelegete的协议为dubbo协议,所以自适应扩展点获取到的实例对象为DubboProtocol,DubboProtocol的执行过程可参考博客Dubbo发布过程中,监听服务的启动,经过DubboProtocol的处理,发布了服务监听,同时返回了一个Dubbo类型的expoter,然后包装成了一个ExporterChangeableWrapper,并加入到了bounds缓存中。至此doLocalExport方法执行完毕。

    private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) {
        String key = getCacheKey(originInvoker);
        ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
        if (exporter == null) {
            synchronized (bounds) {
                exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
                if (exporter == null) {
                    final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
                    exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);
                    bounds.put(key, exporter);
                }
            }
        }
        return exporter;
    }

    private String getCacheKey(final Invoker<?> originInvoker) {
        URL providerUrl = getProviderUrl(originInvoker);
        String key = providerUrl.removeParameters("dynamic", "enabled").toFullString();
        return key;
    }

    private URL getProviderUrl(final Invoker<?> origininvoker) {
        String export = origininvoker.getUrl().getParameterAndDecoded(Constants.EXPORT_KEY);
        if (export == null || export.length() == 0) {
            throw new IllegalArgumentException("The registry export url is null! registry: " + origininvoker.getUrl());
        }

        URL providerUrl = URL.valueOf(export);
        return providerUrl;
    }
}

getRegistry注册服务

内部调用了扩展点的getRegistry方法,此处根据registryUrl获得的registryFactory实例对象是ZookeeperRegistryFactory。

public class RegistryProtocol implements Protocol {
    private RegistryFactory registryFactory;
    /**
    * 基于invoker的address地址,获取一个注册的实例对象
    */
    private Registry getRegistry(final Invoker<?> originInvoker) {
        URL registryUrl = getRegistryUrl(originInvoker);
        return registryFactory.getRegistry(registryUrl);
    }
}

AbstractRegistryFactory抽象父类

此处经过url.setPath方法处理得到的url去除了export参数

zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=user-provider&dubbo=2.6.2&interface=com.alibaba.dubbo.registry.RegistryService&pid=10260&timeout=7200&timestamp=1642064675754

经过url.toServiceString()方法得到key= zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService,首先根据key从缓存里获取registry,如果缓存不存在,则调用createRegistry方法创建一个registry,父类中是一个抽象方法,然后调用实现类ZookeeperRegistryFactory的具体方法返回一个registry。将创建好的registry放入到缓存中

public abstract class AbstractRegistryFactory implements RegistryFactory {

    public Registry getRegistry(URL url) {
        url = url.setPath(RegistryService.class.getName())
                .addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
                .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY);
        String key = url.toServiceString();
        // Lock the registry access process to ensure a single instance of the registry
        LOCK.lock();
        try {
            Registry registry = REGISTRIES.get(key);
            if (registry != null) {
                return registry;
            }
            registry = createRegistry(url);
            if (registry == null) {
                throw new IllegalStateException("Can not create registry " + url);
            }
            REGISTRIES.put(key, registry);
            return registry;
        } finally {
            // Release the lock
            LOCK.unlock();
        }
    }

    protected abstract Registry createRegistry(URL url);
}

ZookeeperRegistryFactory extends AbstractRegistryFactory

使用构造函数构建一个ZookeeperRegistry实例对象,传参有当前要注册的URL和ZookeeperTransporter 扩展点

public class ZookeeperRegistryFactory extends AbstractRegistryFactory {

    private ZookeeperTransporter zookeeperTransporter;

    public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) {
        this.zookeeperTransporter = zookeeperTransporter;
    }

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

}

ZookeeperRegistry

调用zookeeperTransporter扩展点CuratorZookeeperTransporter的connect方法,进行连接,返回一个zkClient对象。添加一个StateListener对象。

public class ZookeeperRegistry extends FailbackRegistry {

    //监听对象
    private final ConcurrentMap<URL, ConcurrentMap<NotifyListener, ChildListener>> zkListeners = new ConcurrentHashMap<URL, ConcurrentMap<NotifyListener, ChildListener>>();
    // client 对象
    private final ZookeeperClient zkClient;

    public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
        // 父类里面定义了重试机制
        super(url);
        if (url.isAnyHost()) {
            throw new IllegalStateException("registry address == null");
        }
        // 默认group为dubbo
        String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
        if (!group.startsWith(Constants.PATH_SEPARATOR)) {
            group = Constants.PATH_SEPARATOR + group;
        }
        //定义根路径为dubbo
        this.root = group;
        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);
                    }
                }
            }
        });
    }
}

super(url) 父类里面定义了重试机制

CuratorZookeeperTransporter
public class CuratorZookeeperTransporter implements ZookeeperTransporter {

    @Override
    public ZookeeperClient connect(URL url) {
        return new CuratorZookeeperClient(url);
    }

}

  • CuratorZookeeperClient构造zookeeperClient
    构造方法内部首先调用了父类的构造函数,返回一个client。
public class CuratorZookeeperClient extends AbstractZookeeperClient<CuratorWatcher> {
    public CuratorZookeeperClient(URL url) {
        super(url);
        try {
            CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
                    .connectString(url.getBackupAddress())
                    .retryPolicy(new RetryNTimes(1, 1000))
                    .connectionTimeoutMs(5000);
            String authority = url.getAuthority();
            if (authority != null && authority.length() > 0) {
                builder = builder.authorization("digest", authority.getBytes());
            }
            client = builder.build();
            client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
                @Override
                public void stateChanged(CuratorFramework client, ConnectionState state) {
                    if (state == ConnectionState.LOST) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.DISCONNECTED);
                    } else if (state == ConnectionState.CONNECTED) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.CONNECTED);
                    } else if (state == ConnectionState.RECONNECTED) {
                        CuratorZookeeperClient.this.stateChanged(StateListener.RECONNECTED);
                    }
                }
            });
            client.start();
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

}
  • AbstractZookeeperClient
public abstract class AbstractZookeeperClient<TargetChildListener> implements ZookeeperClient {

    private final URL url;
    // 状态监听器
    private final Set<StateListener> stateListeners = new CopyOnWriteArraySet<StateListener>();
    // 子节点监听器
    private final ConcurrentMap<String, ConcurrentMap<ChildListener, TargetChildListener>> childListeners = new ConcurrentHashMap<String, ConcurrentMap<ChildListener, TargetChildListener>>();

    public AbstractZookeeperClient(URL url) {
        // url = zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?
        // application=user-provider&dubbo=2.6.2&interface=com.alibaba.dubbo.registry.RegistryService&
        // pid=10260&timeout=7200&timestamp=1642064675754
        this.url = url;
    }
}

ProviderConsumerRegTable.registerProvider

public class ProviderConsumerRegTable {
    public static ConcurrentHashMap<String, Set<ProviderInvokerWrapper>> providerInvokers = new ConcurrentHashMap<String, Set<ProviderInvokerWrapper>>();
    public static ConcurrentHashMap<String, Set<ConsumerInvokerWrapper>> consumerInvokers = new ConcurrentHashMap<String, Set<ConsumerInvokerWrapper>>();

    public static void registerProvider(Invoker invoker, URL registryUrl, URL providerUrl) {
        ProviderInvokerWrapper wrapperInvoker = new ProviderInvokerWrapper(invoker, registryUrl, providerUrl);
        // serviceUniqueName  = com.bail.user.service.IUserService:1.0.0;接口名+版本号
        String serviceUniqueName = providerUrl.getServiceKey();
        // 从缓存中获取提供者invoker,如果为空,则创建一个set对象,保存invoker
        Set<ProviderInvokerWrapper> invokers = providerInvokers.get(serviceUniqueName);
        if (invokers == null) {
            providerInvokers.putIfAbsent(serviceUniqueName, new ConcurrentHashSet<ProviderInvokerWrapper>());
            invokers = providerInvokers.get(serviceUniqueName);
        }
        // 添加invoker对象
        invokers.add(wrapperInvoker);
    }

}

ZookeeperRegistry.register

FailbackRegistry.register

register方法中首先调用了父类AbstractRegistry 的register方法,进行一个服务地址已经注册的缓存标记,接着调用doRegister方法,doRegister在当前类中是一个模板方法,实际上调用的是ZookeeperRegistry的doRegister方法,即具体实现由子类提供

public abstract class FailbackRegistry extends AbstractRegistry {
    public void register(URL url) {
        super.register(url);
        failedRegistered.remove(url);
        failedUnregistered.remove(url);
        try {
            // Sending a registration request to the server side
            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)
                    && !Constants.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);
            }

            // Record a failed registration request to a failed list, retry regularly
            failedRegistered.add(url);
        }
    }
    // ==== Template method ====

    protected abstract void doRegister(URL url);

    protected abstract void doUnregister(URL url);

    protected abstract void doSubscribe(URL url, NotifyListener listener);

    protected abstract void doUnsubscribe(URL url, NotifyListener listener);
}
public abstract class AbstractRegistry implements Registry {
    private final Set<URL> registered = new ConcurrentHashSet<URL>();
    @Override
    public void register(URL url) {
        if (url == null) {
            throw new IllegalArgumentException("register url == null");
        }
        if (logger.isInfoEnabled()) {
            logger.info("Register: " + url);
        }
        registered.add(url);
    }

}

ZookeeperRegistry.doRegister

方法内部调用了zkClient的create方法进行节点创建,此时的url =

经过zkClient.create方法的执行,zookeeper中多了下图路径

其中的路径是在toUrlPath(url)方法中处理生成的

public class ZookeeperRegistry extends FailbackRegistry {
    @Override
    protected void doRegister(URL url) {
        try {
            zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
        } catch (Throwable e) {
            throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

    private String toUrlPath(URL url) {
        return toCategoryPath(url) + Constants.PATH_SEPARATOR + URL.encode(url.toFullString());
    }

    private String toCategoryPath(URL url) {
        return toServicePath(url) + Constants.PATH_SEPARATOR + url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
    }

    private String toServicePath(URL url) {
        String name = url.getServiceInterface();
        if (Constants.ANY_VALUE.equals(name)) {
            return toRootPath();
        }
        return toRootDir() + URL.encode(name);
    }
}

OverrideListener

OverrideListener是RegistryProtocol的一个内部类

public class RegistryProtocol implements Protocol {
    private class OverrideListener implements NotifyListener {
        private final URL subscribeUrl;
        private final Invoker originInvoker;

        public OverrideListener(URL subscribeUrl, Invoker originalInvoker) {
            this.subscribeUrl = subscribeUrl;
            this.originInvoker = originalInvoker;
        }
  }
}

ZookeeperRegistry.subscribe

ZookeeperRegistry

父类的subscribe调用了ZookeeperRegistry 的doSubscribe方法,看一下当前都有哪些动作方法?
在else逻辑中,当前url =

provider://10.9.233.26:20881/com.bail.user.service.IUserService?anyhost=true&application=user-provider&category=configurators&check=false&dubbo=2.6.2&generic=false&getUserById.retries=3&getUserById.timeout=3000&interface=com.bail.user.service.IUserService&methods=getUserById,queryList&pid=24288&retries=2&revision=1.0.0&side=provider&timeout=8000&timestamp=1642126934044&version=1.0.0


调用toCategoriesPath方法得到categoriesPath pahts[0] = "/dubbo/com.bail.user.service.IUserService/configurators"
根据path创建配置节点,为当前路径添加监听者,调用zkClient的addChildListener方法,
根据url, path, children三个参数得到的url如下图

empty://10.9.233.26:20881/com.bail.user.service.IUserService?anyhost=true&application=user-provider&category=configurators&check=false&dubbo=2.6.2&generic=false&getUserById.retries=3&getUserById.timeout=3000&interface=com.bail.user.service.IUserService&methods=getUserById,queryList&pid=24288&retries=2&revision=1.0.0&side=provider&timeout=8000&timestamp=1642126934044&version=1.0.0

获取到urls之后,调用父类FailbackRegistry 的notify方法

public class ZookeeperRegistry extends FailbackRegistry {
    // url对应的订阅者
    private final ConcurrentMap<URL, ConcurrentMap<NotifyListener, ChildListener>> zkListeners = new ConcurrentHashMap<URL, ConcurrentMap<NotifyListener, ChildListener>>();
    protected void doSubscribe(final URL url, final NotifyListener listener) {
        try {
            if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {
                String root = toRootPath();
                ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
                if (listeners == null) {
                    zkListeners.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, ChildListener>());
                    listeners = zkListeners.get(url);
                }
                ChildListener zkListener = listeners.get(listener);
                if (zkListener == null) {
                    listeners.putIfAbsent(listener, new ChildListener() {
                        @Override
                        public void childChanged(String parentPath, List<String> currentChilds) {
                            for (String child : currentChilds) {
                                child = URL.decode(child);
                                if (!anyServices.contains(child)) {
                                    anyServices.add(child);
                                    subscribe(url.setPath(child).addParameters(Constants.INTERFACE_KEY, child,
                                            Constants.CHECK_KEY, String.valueOf(false)), listener);
                                }
                            }
                        }
                    });
                    zkListener = listeners.get(listener);
                }
                zkClient.create(root, false);
                List<String> services = zkClient.addChildListener(root, zkListener);
                if (services != null && !services.isEmpty()) {
                    for (String service : services) {
                        service = URL.decode(service);
                        anyServices.add(service);
                        subscribe(url.setPath(service).addParameters(Constants.INTERFACE_KEY, service,
                                Constants.CHECK_KEY, String.valueOf(false)), listener);
                    }
                }
            } else {
                // url.getServiceInterface() = com.bail.user.service.IUserService,进入else逻辑
                List<URL> urls = new ArrayList<URL>();
                for (String path : toCategoriesPath(url)) {
                    ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
                    if (listeners == null) {
                        zkListeners.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, ChildListener>());
                        listeners = zkListeners.get(url);
                    }
                    // 初始zkListener为空,添加listener对应的子事件,并添加了一个childChanged事件动作,在动作中触发notify方法,通知监听者
                    ChildListener zkListener = listeners.get(listener);
                    if (zkListener == null) {
                        listeners.putIfAbsent(listener, new ChildListener() {
                            @Override
                            public void childChanged(String parentPath, List<String> currentChilds) {
                                ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds));
                            }
                        });
                        zkListener = listeners.get(listener);
                    }
                    // 根据path创建配置节点
                    zkClient.create(path, false);
                    // 为当前路径添加监听者,调用zkClient的addChildListener方法
                    List<String> children = zkClient.addChildListener(path, zkListener);
                    if (children != null) {
                        urls.addAll(toUrlsWithEmpty(url, path, children));
                    }
                }
                notify(url, listener, urls);
            }
        } catch (Throwable e) {
            throw new RpcException("Failed to subscribe " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

    private String[] toCategoriesPath(URL url) {
        String[] categories;
        if (Constants.ANY_VALUE.equals(url.getParameter(Constants.CATEGORY_KEY))) {
            categories = new String[]{Constants.PROVIDERS_CATEGORY, Constants.CONSUMERS_CATEGORY,
                    Constants.ROUTERS_CATEGORY, Constants.CONFIGURATORS_CATEGORY};
        } else {
            categories = url.getParameter(Constants.CATEGORY_KEY, new String[]{Constants.DEFAULT_CATEGORY});
        }
        String[] paths = new String[categories.length];
        for (int i = 0; i < categories.length; i++) {
            paths[i] = toServicePath(url) + Constants.PATH_SEPARATOR + categories[i];
        }
        return paths;
    }
}

notify方法调用了父类的doNotify方法

FailbackRegistry

public abstract class FailbackRegistry extends AbstractRegistry {
    public void subscribe(URL url, NotifyListener listener) {
        // 添加监听者
        super.subscribe(url, listener);
        removeFailedSubscribed(url, listener);
        try {
            // Sending a subscription request to the server side
            // 发布一个订阅请求到服务端,调用子类的具体实现方法
            doSubscribe(url, listener);
        } catch (Exception e) {
            Throwable t = e;

            List<URL> urls = getCacheUrls(url);
            if (urls != null && !urls.isEmpty()) {
                notify(url, listener, urls);
                logger.error("Failed to subscribe " + url + ", Using cached list: " + urls + " from cache file: " + getUrl().getParameter(Constants.FILE_KEY, System.getProperty("user.home") + "/dubbo-registry-" + url.getHost() + ".cache") + ", cause: " + t.getMessage(), t);
            } else {
                // 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);
                boolean skipFailback = t instanceof SkipFailbackWrapperException;
                if (check || skipFailback) {
                    if (skipFailback) {
                        t = t.getCause();
                    }
                    throw new IllegalStateException("Failed to subscribe " + url + ", cause: " + t.getMessage(), t);
                } else {
                    logger.error("Failed to subscribe " + url + ", waiting for retry, cause: " + t.getMessage(), t);
                }
            }

            // Record a failed registration request to a failed list, retry regularly
            addFailedSubscribed(url, listener);
        }
    }

    protected void notify(URL url, NotifyListener listener, List<URL> urls) {
        if (url == null) {
            throw new IllegalArgumentException("notify url == null");
        }
        if (listener == null) {
            throw new IllegalArgumentException("notify listener == null");
        }
        try {
            doNotify(url, listener, urls);
        } catch (Exception t) {
            // Record a failed registration request to a failed list, retry regularly
            Map<NotifyListener, List<URL>> listeners = failedNotified.get(url);
            if (listeners == null) {
                failedNotified.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, List<URL>>());
                listeners = failedNotified.get(url);
            }
            listeners.put(listener, urls);
            logger.error("Failed to notify for subscribe " + url + ", waiting for retry, cause: " + t.getMessage(), t);
        }
    }

    protected void doNotify(URL url, NotifyListener listener, List<URL> urls) {
        super.notify(url, listener, urls);
    }
    // ==== Template method ====

    protected abstract void doRegister(URL url);

    protected abstract void doUnregister(URL url);

    protected abstract void doSubscribe(URL url, NotifyListener listener);

    protected abstract void doUnsubscribe(URL url, NotifyListener listener);
}

AbstractRegistry

在父类中添加前面构建的监听者
public abstract class AbstractRegistry implements Registry {
    public void subscribe(URL url, NotifyListener listener) {
        if (url == null) {
            throw new IllegalArgumentException("subscribe url == null");
        }
        if (listener == null) {
            throw new IllegalArgumentException("subscribe listener == null");
        }
        if (logger.isInfoEnabled()) {
            logger.info("Subscribe: " + url);
        }
        Set<NotifyListener> listeners = subscribed.get(url);
        if (listeners == null) {
            subscribed.putIfAbsent(url, new ConcurrentHashSet<NotifyListener>());
            listeners = subscribed.get(url);
        }
        listeners.add(listener);
    }
}

notify方法中,首先调用了UrlUtils.isMatch(url, u)来判断提供者url和urls中的路径是否匹配,categoryList.add(u)添加当前empty路径

    private final ConcurrentMap<URL, Map<String, List<URL>>> notified = new ConcurrentHashMap<URL, Map<String, List<URL>>>();

    protected void notify(URL url, NotifyListener listener, List<URL> urls) {
        if (url == null) {
            throw new IllegalArgumentException("notify url == null");
        }
        if (listener == null) {
            throw new IllegalArgumentException("notify listener == null");
        }
        if ((urls == null || urls.isEmpty())
                && !Constants.ANY_VALUE.equals(url.getServiceInterface())) {
            logger.warn("Ignore empty notify urls for subscribe url " + url);
            return;
        }
        if (logger.isInfoEnabled()) {
            logger.info("Notify urls for subscribe url " + url + ", urls: " + urls);
        }
        Map<String, List<URL>> result = new HashMap<String, List<URL>>();
        for (URL u : urls) {
            if (UrlUtils.isMatch(url, u)) {
                String category = u.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
                List<URL> categoryList = result.get(category);
                if (categoryList == null) {
                    categoryList = new ArrayList<URL>();
                    result.put(category, categoryList);
                }
                categoryList.add(u);
            }
        }
        if (result.size() == 0) {
            return;
        }
        Map<String, List<URL>> categoryNotified = notified.get(url);
        if (categoryNotified == null) {
            notified.putIfAbsent(url, new ConcurrentHashMap<String, List<URL>>());
            categoryNotified = notified.get(url);
        }
        for (Map.Entry<String, List<URL>> entry : result.entrySet()) {
            String category = entry.getKey();
            List<URL> categoryList = entry.getValue();
            categoryNotified.put(category, categoryList);
            saveProperties(url);
            listener.notify(categoryList);
        }
    }

consumerUrl

provider://10.9.233.26:20881/com.bail.user.service.IUserService?anyhost=true&application=user-provider&category=configurators&check=false&dubbo=2.6.2&generic=false&getUserById.retries=3&getUserById.timeout=3000&interface=com.bail.user.service.IUserService&methods=getUserById,queryList&pid=24288&retries=2&revision=1.0.0&side=provider&timeout=8000&timestamp=1642126934044&version=1.0.0

providerUrl

empty://10.9.233.26:20881/com.bail.user.service.IUserService?anyhost=true&application=user-provider&category=configurators&check=false&dubbo=2.6.2&generic=false&getUserById.retries=3&getUserById.timeout=3000&interface=com.bail.user.service.IUserService&methods=getUserById,queryList&pid=24288&retries=2&revision=1.0.0&side=provider&timeout=8000&timestamp=1642126934044&version=1.0.0

isMatch方法返回true

    public static boolean isMatch(URL consumerUrl, URL providerUrl) {
        // consumerInterface  = providerInterface = com.bail.user.service.IUserService
        String consumerInterface = consumerUrl.getServiceInterface();
        String providerInterface = providerUrl.getServiceInterface();
        if (!(Constants.ANY_VALUE.equals(consumerInterface) || StringUtils.isEquals(consumerInterface, providerInterface)))
            return false;

        if (!isMatchCategory(providerUrl.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY),
                consumerUrl.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY))) {
            return false;
        }
        if (!providerUrl.getParameter(Constants.ENABLED_KEY, true)
                && !Constants.ANY_VALUE.equals(consumerUrl.getParameter(Constants.ENABLED_KEY))) {
            return false;
        }

        String consumerGroup = consumerUrl.getParameter(Constants.GROUP_KEY);
        String consumerVersion = consumerUrl.getParameter(Constants.VERSION_KEY);
        String consumerClassifier = consumerUrl.getParameter(Constants.CLASSIFIER_KEY, Constants.ANY_VALUE);

        String providerGroup = providerUrl.getParameter(Constants.GROUP_KEY);
        String providerVersion = providerUrl.getParameter(Constants.VERSION_KEY);
        String providerClassifier = providerUrl.getParameter(Constants.CLASSIFIER_KEY, Constants.ANY_VALUE);
        return (Constants.ANY_VALUE.equals(consumerGroup) || StringUtils.isEquals(consumerGroup, providerGroup) || StringUtils.isContains(consumerGroup, providerGroup))
                && (Constants.ANY_VALUE.equals(consumerVersion) || StringUtils.isEquals(consumerVersion, providerVersion))
                && (consumerClassifier == null || Constants.ANY_VALUE.equals(consumerClassifier) || StringUtils.isEquals(consumerClassifier, providerClassifier));
    }

zkClient的addChildListener为配置路径添加监听器

AbstractZookeeperClient

createTargetChildListener(path, listener)方法返回一个CuratorWatcherImpl 实例对象。然后调用addTargetChildListener方法

public abstract class AbstractZookeeperClient<TargetChildListener> implements ZookeeperClient {
    // 缓存监听器
    private final ConcurrentMap<String, ConcurrentMap<ChildListener, TargetChildListener>> childListeners = new ConcurrentHashMap<String, ConcurrentMap<ChildListener, TargetChildListener>>();

    // 添加子监听器
    public List<String> addChildListener(String path, final ChildListener listener) {
        // listeners当前为空
        ConcurrentMap<ChildListener, TargetChildListener> listeners = childListeners.get(path);
        if (listeners == null) {
            childListeners.putIfAbsent(path, new ConcurrentHashMap<ChildListener, TargetChildListener>());
            listeners = childListeners.get(path);
        }
        // 当前的目标监听器为空
        TargetChildListener targetListener = listeners.get(listener);
        if (targetListener == null) {
            listeners.putIfAbsent(listener, createTargetChildListener(path, listener));
            targetListener = listeners.get(listener);
        }
        return addTargetChildListener(path, targetListener);
    }

    protected abstract void doClose();

    protected abstract void createPersistent(String path);

    protected abstract void createEphemeral(String path);

    protected abstract boolean checkExists(String path);

    protected abstract TargetChildListener createTargetChildListener(String path, ChildListener listener);

    protected abstract List<String> addTargetChildListener(String path, TargetChildListener listener);

    protected abstract void removeTargetChildListener(String path, TargetChildListener listener);
}
CuratorZookeeperClient

addTargetChildListener 为当前路径添加目标监听器,

public class CuratorZookeeperClient extends AbstractZookeeperClient<CuratorWatcher> {
    private final CuratorFramework client;

    public CuratorWatcher createTargetChildListener(String path, ChildListener listener) {
        return new CuratorWatcherImpl(listener);
    }

    @Override
    public List<String> addTargetChildListener(String path, CuratorWatcher listener) {
        try {
            return client.getChildren().usingWatcher(listener).forPath(path);
        } catch (NoNodeException e) {
            return null;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }
private class CuratorWatcherImpl implements CuratorWatcher {

        private volatile ChildListener listener;

        public CuratorWatcherImpl(ChildListener listener) {
            this.listener = listener;
        }

        public void unwatch() {
            this.listener = null;
        }

        @Override
        public void process(WatchedEvent event) throws Exception {
            if (listener != null) {
                String path = event.getPath() == null ? "" : event.getPath();
                listener.childChanged(path,
                        // if path is null, curator using watcher will throw NullPointerException.
                        // if client connect or disconnect to server, zookeeper will queue
                        // watched event(Watcher.Event.EventType.None, .., path = null).
                        StringUtils.isNotEmpty(path)
                                ? client.getChildren().usingWatcher(this).forPath(path)
                                : Collections.<String>emptyList());
            }
        }
    }
}
posted @ 2022-01-16 23:26  南宫煌_慧  阅读(266)  评论(0编辑  收藏  举报