Dubbo源码分析之消费端

知识共享许可协议 版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

dubbo的xml配置文件<dubbo:reference>对应的就是ReferenceBean,它实现了FactoryBean,所以在初始化实例时就会调用他的实现方法,从而开启服务引用


public Object getObject() {
    return get();
}

检查必要的配置信息,加载注册中心URL,拼装引用URL。

checkRegistry();
List<URL> us = loadRegistries(false);
if (CollectionUtils.isNotEmpty(us)) {
    for (URL u : us) {
        URL monitorUrl = loadMonitor(u);
        if (monitorUrl != null) {
            map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
        }
        urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
    }
}
if (urls.isEmpty()) {
    throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config.");
}

服务引用

invoker = refprotocol.refer(interfaceClass, urls.get(0));

还原原始的注册协议,获取注册中心,默认为zookeeper

public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    url = URLBuilder.from(url)
            .setProtocol(url.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY))
            .removeParameter(REGISTRY_KEY)
            .build();
    Registry registry = registryFactory.getRegistry(url);
    if (RegistryService.class.equals(type)) {
        return proxyFactory.getInvoker((T) registry, type, url);
    }

    // group="a,b" or group="*"
    Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
    String group = qs.get(Constants.GROUP_KEY);
    if (group != null && group.length() > 0) {
        if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
            return doRefer(getMergeableCluster(), registry, type, url);
        }
    }
    return doRefer(cluster, registry, type, url);
}

服务引用最后返回invoker代理

private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
    RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
    directory.setRegistry(registry);
    directory.setProtocol(protocol);
    // all attributes of REFER_KEY
    Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters());
    URL subscribeUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
    if (!ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(REGISTER_KEY, true)) {
        directory.setRegisteredConsumerUrl(getRegisteredConsumerUrl(subscribeUrl, url));
        registry.register(directory.getRegisteredConsumerUrl());
    }
    directory.buildRouterChain(subscribeUrl);
    directory.subscribe(subscribeUrl.addParameter(CATEGORY_KEY,
            PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY));

    Invoker invoker = cluster.join(directory);
    ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory);
    return invoker;
}

创建注册明细类,核心类,主要包含可用的提供端invoker等信息,解析出消费端的查询参数,主要用来和提供端URL参数进行合并覆盖,判断是否是多组设置。

public RegistryDirectory(Class<T> serviceType, URL url) {
    super(url);
    if (serviceType == null) {
        throw new IllegalArgumentException("service type is null.");
    }
    if (url.getServiceKey() == null || url.getServiceKey().length() == 0) {
        throw new IllegalArgumentException("registry serviceKey is null.");
    }
    this.serviceType = serviceType;
    this.serviceKey = url.getServiceKey();
    this.queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY));
    this.overrideDirectoryUrl = this.directoryUrl = turnRegistryUrlToConsumerUrl(url);
    String group = directoryUrl.getParameter(Constants.GROUP_KEY, "");
    this.multiGroup = group != null && (Constants.ANY_VALUE.equals(group) || group.contains(","));
}

设置消费端URL以及路由链

public AbstractDirectory(URL url) {
    this(url, null);
}

public AbstractDirectory(URL url, RouterChain<T> routerChain) {
    this(url, url, routerChain);
}

public AbstractDirectory(URL url, URL consumerUrl, RouterChain<T> routerChain) {
    if (url == null) {
        throw new IllegalArgumentException("url == null");
    }

    if (url.getProtocol().equals(Constants.REGISTRY_PROTOCOL)) {
        Map<String, String> queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY));
        this.url = url.addParameters(queryMap).removeParameter(Constants.MONITOR_KEY);
    } else {
        this.url = url;
    }

    this.consumerUrl = consumerUrl;
    setRouterChain(routerChain);
}

组装原始的消费端URL并且获取需要进行注册的消费端URL,并注册到注册中心


public URL getRegisteredConsumerUrl(final URL consumerUrl, URL registryUrl) {
    if (!registryUrl.getParameter(SIMPLIFIED_KEY, false)) {
        return consumerUrl.addParameters(CATEGORY_KEY, CONSUMERS_CATEGORY,
                CHECK_KEY, String.valueOf(false));
    } else {
        return URL.valueOf(consumerUrl, DEFAULT_REGISTER_CONSUMER_KEYS, null).addParameters(
                CATEGORY_KEY, CONSUMERS_CATEGORY, CHECK_KEY, String.valueOf(false));
    }
}

构建路由链


public void buildRouterChain(URL url) {
    this.setRouterChain(RouterChain.buildChain(url));
}

public static <T> RouterChain<T> buildChain(URL url) {
    return new RouterChain<>(url);
}

获取所有激活的满足要求的路由工厂


private RouterChain(URL url) {
    List<RouterFactory> extensionFactories = ExtensionLoader.getExtensionLoader(RouterFactory.class)
            .getActivateExtension(url, (String[]) null);

    List<Router> routers = extensionFactories.stream()
            .map(factory -> factory.getRouter(url))
            .collect(Collectors.toList());

    initWithRouters(routers);
}

分别为以下四个,进行排序后保存。

class MockRouterFactory
public Router getRouter(URL url) {
    return new MockInvokersSelector();
}

class TagRouterFactory extends CacheableRouterFactory
public Router getRouter(URL url) {
    routerMap.computeIfAbsent(url.getServiceKey(), k -> createRouter(url));
    return routerMap.get(url.getServiceKey());
}
protected Router createRouter(URL url) {
    return new TagRouter(DynamicConfiguration.getDynamicConfiguration(), url);
}

class AppRouterFactory 
public Router getRouter(URL url) {
    if (router != null) {
        return router;
    }
    synchronized (this) {
        if (router == null) {
            router = createRouter(url);
        }
    }
    return router;
}

private Router createRouter(URL url) {
    return new AppRouter(DynamicConfiguration.getDynamicConfiguration(), url);
}

class ServiceRouterFactory extends CacheableRouterFactory
protected Router createRouter(URL url) {
    return new ServiceRouter(DynamicConfiguration.getDynamicConfiguration(), url);
}

订阅节点信息"providers","consumers","routers",重置消费端URL信息,开始订阅,监听器为注册明细类。


public void subscribe(URL url) {
    setConsumerUrl(url);
    consumerConfigurationListener.addNotifyListener(this);
    serviceConfigurationListener = new ReferenceConfigurationListener(this, url);
    registry.subscribe(url, this);
}

保存URL于监听器的对应关系


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.computeIfAbsent(url, n -> new ConcurrentHashSet<>());
    listeners.add(listener);
}

移除相对应的订阅失败的URL,取消订阅失败URL,失败通知URL等信息


public void subscribe(URL url, NotifyListener listener) {
    super.subscribe(url, listener);
    removeFailedSubscribed(url, listener);
     // Sending a subscription request to the server side
    doSubscribe(url, listener);
}

开始订阅,获取不同的类别路径,这就会有上面那三个路径信息


List<URL> urls = new ArrayList<>();
for (String path : toCategoriesPath(url)) {
  ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
  if (listeners == null) {
      zkListeners.putIfAbsent(url, new ConcurrentHashMap<>());
      listeners = zkListeners.get(url);
  }
  ChildListener zkListener = listeners.get(listener);
  if (zkListener == null) {
      listeners.putIfAbsent(listener, (parentPath, currentChilds) -> ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds)));
      zkListener = listeners.get(listener);
  }
  zkClient.create(path, false);
  List<String> children = zkClient.addChildListener(path, zkListener);
  if (children != null) {
      urls.addAll(toUrlsWithEmpty(url, path, children));
  }
}
notify(url, listener, urls);

创建该节点并设置对应的子节点监听器,后续会通过节点的变更来更新对提供端的invoker代理

public List<String> addChildListener(String path, final ChildListener listener) {
    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);
}

public CuratorZookeeperClient.CuratorWatcherImpl createTargetChildListener(String path, ChildListener listener) {
    return new CuratorZookeeperClient.CuratorWatcherImpl(client, listener);
}

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

给注册明细类添加集群策略包装成本地invoker代理

public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
    return new FailoverClusterInvoker<T>(directory);
}

public AbstractClusterInvoker(Directory<T> directory) {
    this(directory, directory.getUrl());
}

public AbstractClusterInvoker(Directory<T> directory, URL url) {
    if (directory == null) {
        throw new IllegalArgumentException("service directory == null");
    }

    this.directory = directory;
    //sticky: invoker.isAvailable() should always be checked before using when availablecheck is true.
    this.availablecheck = url.getParameter(Constants.CLUSTER_AVAILABLE_CHECK_KEY, Constants.DEFAULT_CLUSTER_AVAILABLE_CHECK);
}

创建服务引用代理返回


(T) proxyFactory.getProxy(invoker);

public <T> T getProxy(Invoker<T> invoker) throws RpcException {
    return getProxy(invoker, false);
}

public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}

猜你喜欢

转载自blog.csdn.net/ph3636/article/details/91868791