服务消费端Directory目录的创建与更新

1 Directory目录概述

Directory代表多个invoker,其内部维护了一个list,并且这个list的内容时动态变化的(对于消费端来说,每个invoker代表一个服务提供者)。

在Dubbo中,RegistryDirectory和StaticDirectory都是Directory的实现类。

RegistryDirectory是一个动态服务目录,可以感知注册中心配置的变化,其持有的Invoker列表会随着注册中心内容的变化而变化。每次变化后,RegistryDirectory都会动态地增删Invoker,并调用Router的route方法进行路由,过滤掉不符合路由规则的Invoker。相反,StaticDirectory是一个静态服务目录,它内部存放的Invoker是不会变动的。

RegistryDirectory是Dubbo中默认使用的Directory,适用于服务提供者和消费者都动态变化的情况。而StaticDirectory适用于服务提供者和消费者相对固定,不需要频繁变动的场景。

2 RegistryDirectory的创建

RegistryDirectory是在服务消费端启动时创建的。

消费端启动时,通过 ReferenceConfig#get() 创建对服务提供方的远程调用代理类。最终在通过RegistryProtocol#refer() 创建invoker时创建了RegistryDirectory。具体实现细节如下所示。

     public T get(boolean check) {
        // ...

        return ref;
    }   


    protected synchronized void init(boolean check) {
            // ...

            // 创建对服务提供方的远程调用代理类
            ref = createProxy(referenceParameters);

            // ...
    }


    private T createProxy(Map referenceParameters) {
        // ...

        // 创建invoker
        createInvoker();

        // ...

        // create service proxy
        return (T) proxyFactory.getProxy(invoker, ProtocolUtils.isGeneric(generic));
    }


    private void createInvoker() {
        if (urls.size() == 1) {
            URL curUrl = urls.get(0);
            invoker = protocolSPI.refer(interfaceClass, curUrl);
            
            // ...
        } else {
            List> invokers = new ArrayList<>();
            URL registryUrl = null;
            for (URL url : urls) {
                invokers.add(protocolSPI.refer(interfaceClass, url));

                if (UrlUtils.isRegistry(url)) {
                    // use last registry url
                    registryUrl = url;
                }
            }

            // ...
        }
    }

创建invoker的核心方法为 

invoker = protocolSPI.refer(interfaceClass, curUrl);

服务注册和发现使用是register协议,因此上述方法实际上将调用 RegistryProtocol#refer方法,实现如下所示。

    public  Invoker refer(Class type, URL url) throws RpcException {
        url = getRegistryUrl(url);
        Registry registry = getRegistry(url);
        if (RegistryService.class.equals(type)) {
            return proxyFactory.getInvoker((T) registry, type, url);
        }

        // group="a,b" or group="*"
        Map qs = (Map) url.getAttribute(REFER_KEY);
        String group = qs.get(GROUP_KEY);
        if (StringUtils.isNotEmpty(group)) {
            if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
                return doRefer(Cluster.getCluster(url.getScopeModel(), MergeableCluster.NAME), registry, type, url, qs);
            }
        }

        Cluster cluster = Cluster.getCluster(url.getScopeModel(), qs.get(CLUSTER_KEY));

        // 创建invoker
        return doRefer(cluster, registry, type, url, qs);
    }


    protected  Invoker doRefer(Cluster cluster, Registry registry, Class type, URL url, Map parameters) {
        // ...

        // 创建invoker
        ClusterInvoker migrationInvoker = getMigrationInvoker(this, cluster, registry, type, url, consumerUrl);
        return interceptInvoker(migrationInvoker, url, consumerUrl);
    }

最终将调用下述方法创建RegistryDirectory。

    public  ClusterInvoker getInvoker(Cluster cluster, Registry registry, Class type, URL url) {
        DynamicDirectory directory = new RegistryDirectory<>(type, url);
        return doCreateInvoker(directory, cluster, registry, type);
    }

3 RegistryDirectory中invoker列表的更新

你可能感兴趣的:(dubbo,Directory,invoker列表)