五Dubbo服务引用源码分析--2创建远程调用的代理-2.3zookeeperRegistry.subscribe订阅

五Dubbo服务引用源码分析--2创建远程调用的代理-2.3zookeeperRegistry.subscribe订阅

/**…………………订阅-通知…………………… */
//REFER2.2.3.1 zookeeperRegistry.subscribe-订阅SUB

listener参数是registryDirectory。

FailbackRegistry
    @Override
    public void subscribe(URL url, NotifyListener listener) {
//SUB1 abstractRegistry.subscribe---将listener加入缓存
        super.subscribe(url, listener);
        removeFailedSubscribed(url, listener);
        try {
//SUB2 doSubscribe
            // 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);
                }
            }
						//将失败的订阅请求添加到failedlist,并定时的重试
            addFailedSubscribed(url, listener);
        }
    }

//SUB1 abstractRegistry.subscribe
abstractRegistry.subscribe
  //该缓存中,存储消费者url以及其对应的NotifyListener集合--即registryDirectory集合,在订阅变化的时候,进行通知
 private final ConcurrentMap<URL, Set<NotifyListener>> subscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>();

    @Override
    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);
        }
      //将registryDirectory加入subscribed缓存中
        listeners.add(listener);
    }

subscribed存储的关系,key为消费者consumerURL,value为该消费者的registryDirectory(其也是一个NotifyListener对象),该directory中存储consumer需要引用的invoker的列表。此外,还具有订阅-通知的更新操作,在监听到provider端有服务变化时候,会进行通知,并修改invokers列表。

//SUB2 ZookeeperRegistry.doSubscribe

传入的url参数如下:

image-20221230120148778
ZookeeperRegistry
  @Override
    protected void doSubscribe(final URL url, final NotifyListener listener) {
        try {
/**…………………………………………………………………………消费者消费服务接口为anyValue-*的情况…………………………………………………………………………………………………………………… */
            if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {//DemoService
                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);
                    }
                }
            } 
/**…………………………………………………………………………………………………………处理consume特定接口服务情况………………………………………………………………………………………………………… */
          else { //0
                List<URL> urls = new ArrayList<URL>();
            //此时,消费者订阅服务,category设置表示需要订阅providers/configurators/routers节点下的数据,因此,解析后:
            ///dubbo/com.alibaba.dubbo.demo.DemoService/providers
            ///dubbo/com.alibaba.dubbo.demo.DemoService/configurators
            ///dubbo/com.alibaba.dubbo.demo.DemoService/routers
                for (String path : toCategoriesPath(url)) { //1
//  private final ConcurrentMap<URL, ConcurrentMap<NotifyListener, ChildListener>> zkListeners = new ConcurrentHashMap<URL, ConcurrentMap<NotifyListener, ChildListener>>();
//存储zookeeper存储路径上的对应的两个监听器,一个NotifyListener对应一个ChildListener
                    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) { //2 
                        listeners.putIfAbsent(listener, new ChildListener() {//3 
                            @Override
                            public void childChanged(String parentPath, List<String> currentChilds) {
/**……………………………………………………………………………………zookeeper上节点监听、并通知的原理…………………………………………………………………………………………………… */
                              //创建child节点监听,在节点发生变化时,执行本地方法的notify通知
                                ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds));
                            }
                        });//3 
                        zkListener = listeners.get(listener); //获取registryDirectory对应的zk监听器
                    }//2 
                    zkClient.create(path, false); //如果providers/configurators/routers节点不存在,创建永久节点
                  
/**……………………………………………………………………………………为providers/configurators/routers节点增加child监听器…………………………………………………………………… */
                  //向zk对应节点添加监听器,然后交给zkclient、curator等不同的客户端实现,对应框架的watcherImpl包裹实现监听
                  //返回child节点的信息,对于providers节点,监听其子节点并返回子节点服务
//dubbo%3A%2F%2F192.168.0.101%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemotest-provider%26bean.name%3Dcom.alibaba.dubbo.demo.DemoService%26dubbo%3D2.0.2%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DgetPermissions%26organization%3Ddubbox%26owner%3Dprogrammer%26pid%3D77622%26side%3Dprovider%26timestamp%3D1671863715420
                    List<String> children = zkClient.addChildListener(path, zkListener);
                    if (children != null) {
//SUB2.1 toUrlsWithEmpty(url, path, children)  获取消费端所需要消费的url集合
                        urls.addAll(toUrlsWithEmpty(url, path, children));
                    }
                }//1 
//SUB2.2 notify(url, listener, urls)
                notify(url, listener, urls);
            }//0 
        } catch (Throwable e) {
            throw new RpcException("Failed to subscribe " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

这里,subscribe订阅的逻辑如下:

1对于一个consumerURL消费者,需要关注routers、configurators、providers的节点上的数据;

2 ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);为一个registryDirectory的dubbo监听器和zookeeper上的子节点监听器ChildListener的一对一关系。分别在zookeeper上的routers、configurators、providers节点注册子节点监听器childListener,然后,如果这三个路径中,有节点的子节点发生变化,就会执行ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds))通知;

3

//SUB2.1 toUrlsWithEmpty(url, path, children)

这里,是将zookeeper上注册的providers服务,首先与consumer所需要引用的条件进行匹配,如果匹配成功,返回;

如果zookeeper上注册的服务,没有consumer所需要引用的,那么将consumerURL更改协议头为empty,然后添加category到url中。

返回的list,是匹配到的服务端的url(可能为empty,当访问routers/configurators路径下的节点,toUrlsWithoutEmpty返回null,此时会把consumer设置为empty放入urls中返回)

ZookeeperRegistry
  
private List<URL> toUrlsWithEmpty(URL consumer, String path, List<String> providers) {
  //返回providers提供的服务,与消费者需要的服务向匹配的url
        List<URL> urls = toUrlsWithoutEmpty(consumer, providers);
        if (urls == null || urls.isEmpty()) {
            int i = path.lastIndexOf('/');
            String category = i < 0 ? path : path.substring(i + 1);
          //如果zookeeper上providers上注册的服务,不是consumer所需要引用的,就将consumer://设置为empty,并添加category参数,然后加入zookeeperRegistry上的urls结果中(urls结果表示消费者需要引用的服务url的集合)
            URL empty = consumer.setProtocol(Constants.EMPTY_PROTOCOL).addParameter(Constants.CATEGORY_KEY, category);
            urls.add(empty);
        }
        return urls;
    }

   private List<URL> toUrlsWithoutEmpty(URL consumer, List<String> providers) {
        List<URL> urls = new ArrayList<URL>();
        if (providers != null && !providers.isEmpty()) {
            for (String provider : providers) {
              //将zookeeper上注册的providers服务,解码
//dubbo://192.168.0.101:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demotest-provider&bean.name=com.alibaba.dubbo.demo.DemoService&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=77622&side=provider&timestamp=1671863715420
                provider = URL.decode(provider);
                if (provider.contains("://")) {
                    URL url = URL.valueOf(provider);
                  //判断providerurl是否是consumer需要消费的服务(分别从服务接口、category、group等进行判断)
                    if (UrlUtils.isMatch(consumer, url)) {
                        urls.add(url);
                    }
                }
            }
        }
        return urls;
    }
//SUB2.2 notify(url, listener, urls)

在执行notify通知前,urls中的服务url为:

image-20221230130729574

image-20221230131203730

FailbackRegistry
    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) {
          //记录通知失败的url,存入失败集合failedNotified。然后定时的重试
            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);
    }
AbstractRegistry

    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) { //1 
           //判断providerurl是否是consumer需要消费的服务(分别从服务接口、category、group等进行判断)
          //对于empty://协议,其从consumer转换过来,因此会匹配
            if (UrlUtils.isMatch(url, u)) { //2 
              
                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);
            } //2 
        } //1
        if (result.size() == 0) {
            return;
        }
  		//notified为AbstractRegistry上的内存缓存,存储了zookeeper上的全量信息。
        Map<String, List<URL>> categoryNotified = notified.get(url);
        if (categoryNotified == null) {
            notified.putIfAbsent(url, new ConcurrentHashMap<String, List<URL>>());
            categoryNotified = notified.get(url);
        }
  //遍历result中configurators、routers、providers上对应的url地址
        for (Map.Entry<String, List<URL>> entry : result.entrySet()) {
            String category = entry.getKey();
            List<URL> categoryList = entry.getValue(); //rusult的category对应的url的list
            categoryNotified.put(category, categoryList);
//SUB2.2.1 saveProperties 文件缓存存储
            saveProperties(url);
//SUB2.2.2 listener.notify(categoryList)
            listener.notify(categoryList);
        }
    }

result为:

image-20221230131959105

此时,notified为:

image-20221230160313141

//SUB2.2.1 saveProperties 文件缓存存储

文件缓存中,把notified这一内存缓存上的所有url全部添加到properties上,是全量增加并更新,然后将其写入file文件存储中去。

   private void saveProperties(URL url) {
        if (file == null) {
            return;
        }

        try {
            StringBuilder buf = new StringBuilder();
            Map<String, List<URL>> categoryNotified = notified.get(url);
          //可知文件缓存是全量增加,每次把notified上的notified.get(url).values全量追加,并增加到properties上
            if (categoryNotified != null) {
                for (List<URL> us : categoryNotified.values()) {
                    for (URL u : us) {
                        if (buf.length() > 0) {
                            buf.append(URL_SEPARATOR);
                        }
                        buf.append(u.toFullString());
                    }
                }
            }
          //将demoservice和对应的所有url,存入properties属性对上
            properties.setProperty(url.getServiceKey(), buf.toString());
            long version = lastCacheChanged.incrementAndGet();//提供版本更新的保存,如果版本过低,直接抛弃
/**……………………………………………………………………………………………………文件存储,提供同步保存和异步保存…………………………………………………………………………………………………… */
            if (syncSaveFile) {
                doSaveProperties(version);
            } else {
              //异步执行,通过executor框架实现
                registryCacheExecutor.execute(new SaveProperties(version));
            }
        } catch (Throwable t) {
            logger.warn(t.getMessage(), t);
        }
    }
    public void doSaveProperties(long version) {
        if (version < lastCacheChanged.get()) {
            return;//版本过低,直接抛弃
        }
        if (file == null) {
            return;
        }
        // Save
        try {
          //创建同名的文件所lock
            File lockfile = new File(file.getAbsolutePath() + ".lock");
            if (!lockfile.exists()) {
                lockfile.createNewFile();
            }
            RandomAccessFile raf = new RandomAccessFile(lockfile, "rw");
            try {
                FileChannel channel = raf.getChannel();
                try {
                    FileLock lock = channel.tryLock();
                    if (lock == null) {
                        throw new IOException("Can not lock the registry cache file " + file.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.registry.file=xxx.properties");
                    }
                    // Save
                    try {
                        if (!file.exists()) {
                            file.createNewFile();
                        }
                        FileOutputStream outputFile = new FileOutputStream(file);
                        try {
                          //将properties属性存入文件流
                            properties.store(outputFile, "Dubbo Registry Cache");
                        } finally {
                            outputFile.close();
                        }
                    } finally {
                        lock.release();
                    }
                } finally {
                    channel.close();
                }
            } finally {
                raf.close();
            }
        } catch (Throwable e) {
            if (version < lastCacheChanged.get()) {
                return;
            } else {
                registryCacheExecutor.execute(new SaveProperties(lastCacheChanged.incrementAndGet()));
            }
            logger.warn("Failed to save registry store file, cause: " + e.getMessage(), e);
        }
    }
//SUB2.2.2 listener(即RegistryDirectory).notify(categoryList)
RegistryDirectory
 public synchronized void notify(List<URL> urls) {
/**……………………………………………………………………………………………………将consumer订阅的数据,分类存储……………………………………………………………………………………………………… */
  //consumer订阅zookeeper中providers/routers/configurators节点下数据,在通知这里,分别对应如下的list<URL>集合
        List<URL> invokerUrls = new ArrayList<URL>(); //providers节点下数据
        List<URL> routerUrls = new ArrayList<URL>();
        List<URL> configuratorUrls = new ArrayList<URL>();
        for (URL url : urls) {
            String protocol = url.getProtocol();
            String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
            if (Constants.ROUTERS_CATEGORY.equals(category)
                    || Constants.ROUTE_PROTOCOL.equals(protocol)) {
                routerUrls.add(url);
            } else if (Constants.CONFIGURATORS_CATEGORY.equals(category)
                    || Constants.OVERRIDE_PROTOCOL.equals(protocol)) {
                configuratorUrls.add(url);
            } else if (Constants.PROVIDERS_CATEGORY.equals(category)) {
                invokerUrls.add(url);
            } else {
                logger.warn("Unsupported category " + category + " in notified url: " + url + " from registry " + getUrl().getAddress() + " to consumer " + NetUtils.getLocalHost());
            }
        }
  
        // configurators的处理
        if (configuratorUrls != null && !configuratorUrls.isEmpty()) {
          /**在调用时候,将override urls转换的协议:
     *             </br>1.override://0.0.0.0/...( or override://ip:port...?anyhost=true)&para1=value1... means global rules (all of the providers take effect)
     *             </br>2.override://ip:port...?anyhost=false Special rules (only for a certain provider)
     *             </br>3.override:// rule is not supported... ,needs to be calculated by registry itself.
     *             </br>4.override://0.0.0.0/ without parameters means clearing the override */
            this.configurators = toConfigurators(configuratorUrls);//empty://不处理
        }
        // routers的处理
        if (routerUrls != null && !routerUrls.isEmpty()) {
            List<Router> routers = toRouters(routerUrls);//empty://不处理
            if (routers != null) { // null - do nothing
                setRouters(routers);
            }
        }
        List<Configurator> localConfigurators = this.configurators; // local reference
        // merge override parameters
        this.overrideDirectoryUrl = directoryUrl;
        if (localConfigurators != null && !localConfigurators.isEmpty()) {
            for (Configurator configurator : localConfigurators) {
                this.overrideDirectoryUrl = configurator.configure(overrideDirectoryUrl);
            }
        }
//SUB2.2.2.1 refreshInvoker
        refreshInvoker(invokerUrls);
    }
//SUB2.2.2.1 refreshInvoker(invokerUrls)--刷新invoker

方法把invokerUrls转换为invoker的map集合。转换规则如下:

1 如果invokerUrls已经转换位invoker,那么不再重新引用,并直接从cache获取(url任何参数更改,都需要重新引用,即构建invoker);

2 如果invokerUrls不为空,表示为最新的invokerUrls;

3 如果传入的invokerUrls为空,表示该规则为override覆盖规则或者route路由规则。需要重新对比,以决定是否重新引用。

    private void refreshInvoker(List<URL> invokerUrls) {
      //如果invokerURL为empty://,则关闭invoker情况
        if (invokerUrls != null && invokerUrls.size() == 1 && invokerUrls.get(0) != null
                && Constants.EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {
            this.forbidden = true; // Forbid to access
            this.methodInvokerMap = null; // Set the method invoker map to null
            destroyAllInvokers(); // Close all invokers
        } else {
            this.forbidden = false; // Allow to access
            Map<String, Invoker<T>> oldUrlInvokerMap = this.urlInvokerMap; // local reference
            if (invokerUrls.isEmpty() && this.cachedInvokerUrls != null) {
                invokerUrls.addAll(this.cachedInvokerUrls);
            } else {
                this.cachedInvokerUrls = new HashSet<URL>();
                this.cachedInvokerUrls.addAll(invokerUrls);//如果invokersUrls不为null,加入缓存(方便对比)
            }
            if (invokerUrls.isEmpty()) {//直接返回
                return;
            }
//SUB2.2.2.1.1 toInvokers(invokerUrls)
            Map<String, Invoker<T>> newUrlInvokerMap = toInvokers(invokerUrls);// Translate url list to Invoker map
//SUB2.2.2.1.2 toMethodInvokers(newUrlInvokerMap)
            Map<String, List<Invoker<T>>> newMethodInvokerMap = toMethodInvokers(newUrlInvokerMap); // Change method name to map Invoker Map
            // state change
            // If the calculation is wrong, it is not processed.
            if (newUrlInvokerMap == null || newUrlInvokerMap.size() == 0) {
                logger.error(new IllegalStateException("urls to invokers error .invokerUrls.size :" + invokerUrls.size() + ", invoker.size :0. urls :" + invokerUrls.toString()));
                return;
            }
            this.methodInvokerMap = multiGroup ? toMergeMethodInvokerMap(newMethodInvokerMap) : newMethodInvokerMap;
            this.urlInvokerMap = newUrlInvokerMap;
            try {
                destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); // Close the unused Invoker
            } catch (Exception e) {
                logger.warn("destroyUnusedInvokers error. ", e);
            }
        }
    }
//SUB2.2.2.1.1 toInvokers(invokerUrls)

当invokerURLs不为null时,dubbo://192.168.0.100:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demotest-provider&bean.name=com.alibaba.dubbo.demo.DemoService&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=73971&side=provider&timestamp=1672381137107

RegistryDirectory
 private Map<String, Invoker<T>> toInvokers(List<URL> urls) {
        Map<String, Invoker<T>> newUrlInvokerMap = new HashMap<String, Invoker<T>>();
        if (urls == null || urls.isEmpty()) {
            return newUrlInvokerMap;
        }
        Set<String> keys = new HashSet<String>();
        String queryProtocols = this.queryMap.get(Constants.PROTOCOL_KEY);
        for (URL providerUrl : urls) {
            // If protocol is configured at the reference side, only the matching protocol is selected
            if (queryProtocols != null && queryProtocols.length() > 0) {
                boolean accept = false;
                String[] acceptProtocols = queryProtocols.split(",");
                for (String acceptProtocol : acceptProtocols) {
                    if (providerUrl.getProtocol().equals(acceptProtocol)) {
                        accept = true;
                        break;
                    }
                }
                if (!accept) {
                    continue;
                }
            }
            if (Constants.EMPTY_PROTOCOL.equals(providerUrl.getProtocol())) {
                continue;
            }
            if (!ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(providerUrl.getProtocol())) {
                logger.error(new IllegalStateException("Unsupported protocol " + providerUrl.getProtocol() + " in notified url: " + providerUrl + " from registry " + getUrl().getAddress() + " to consumer " + NetUtils.getLocalHost()
                        + ", supported protocol: " + ExtensionLoader.getExtensionLoader(Protocol.class).getSupportedExtensions()));
                continue;
            }
/**…………………………………………………………………………构造cache key……………………………………………………………… */
            URL url = mergeUrl(providerUrl);//将参数对,合并加入providerurl中

            String key = url.toFullString(); // The parameter urls are sorted
            if (keys.contains(key)) { // keys保存了是否引用过
                continue;
            }
            keys.add(key);
            // Cache key is url that does not merge with consumer side parameters, regardless of how the consumer combines parameters, if the server url changes, then refer again
            Map<String, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap; // local reference
            Invoker<T> invoker = localUrlInvokerMap == null ? null : localUrlInvokerMap.get(key);
          
            if (invoker == null) { // 如果缓存中没有,重新refer引用
                try {
                    boolean enabled = true;
                    if (url.hasParameter(Constants.DISABLED_KEY)) {
                        enabled = !url.getParameter(Constants.DISABLED_KEY, false);
                    } else {
                        enabled = url.getParameter(Constants.ENABLED_KEY, true);
                    }
                    if (enabled) {
//Invoker InvokerDelegate<T>(protocol.refer(serviceType, url), url, providerUrl) 构造invoker
                        invoker = new InvokerDelegate<T>(protocol.refer(serviceType, url), url, providerUrl);
                    }
                } catch (Throwable t) {
                    logger.error("Failed to refer invoker for interface:" + serviceType + ",url:(" + url + ")" + t.getMessage(), t);
                }
                if (invoker != null) { // Put new invoker in cache
                    newUrlInvokerMap.put(key, invoker);
                }
            } else {
                newUrlInvokerMap.put(key, invoker);
            }
        }
        keys.clear();
        return newUrlInvokerMap;
    }

在toInvokers(invokerUrls)方法中,主要是构造invoker

    private static class InvokerDelegate<T> extends InvokerWrapper<T> {
        private URL providerUrl;
//dubbo://192.168.0.100:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demotest-consumer&bean.name=com.alibaba.dubbo.demo.DemoService&check=false&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=75508&qos.enable=false&register.ip=192.168.0.100&remote.timestamp=1672381137107&side=consumer&timestamp=1672387055607
        public InvokerDelegate(Invoker<T> invoker, URL url, URL providerUrl) {
            super(invoker, url);
//dubbo://192.168.0.100:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demotest-provider&bean.name=com.alibaba.dubbo.demo.DemoService&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=getPermissions&organization=dubbox&owner=programmer&pid=73971&side=provider&timestamp=1672381137107
            this.providerUrl = providerUrl;
        }
        
     public InvokerWrapper(Invoker<T> invoker, URL url) {
        this.invoker = invoker;
        this.url = url;
    }
      
posted @ 2023-03-13 14:46  LeasonXue  阅读(106)  评论(0编辑  收藏  举报