Dubbo Learning Record (17) - Service Invocation [3] - Packaging of Invoker on the service consumer side

Packaging of Invoker on the service consumer side

The Invoker on the service consumer side involves the service export process, and a proxy instance Invoker is generated by the ReferenceConfigde#get() method to return; the purpose of
this time is to clear up the entire packaging link;

ReferenceConfigde#get()

The exported logic is all in the init method;

    public synchronized T get() {
    
    
        checkAndUpdateSubConfigs();
        if (ref == null) {
    
    
            // 入口
            init();
        }
        return ref;  // Invoke代理
    }
    //下一层createProxy(map)
    private void init() {
    
    

        Map<String, String> map = new HashMap<String, String>();
		//省略参数获取过程;
        // 得到一个代理对象
        ref = createProxy(map);
    }
	
     private T createProxy(Map<String, String> map) {
    
    
        if (shouldJvmRefer(map)) {
    
    
        //省略部分代码
        } else {
    
    
            // @Reference中指定了url属性
            if (url != null && url.length() > 0) {
    
    
            //省略部分代码
                }
            } else {
    
    
      		 // 加载注册中心地址,省略部分代码
            }

            // 如果只有一个url则直接refer得到一个invoker
            if (urls.size() == 1) {
    
    
                // RegistryProtocol.refer() 或者 DubboProtocol.refer()
                invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
            } else {
    
    
                // 如果有多个url
                // 1. 根据每个url,refer得到对应的invoker
                // 2. 如果这多个urls中存在注册中心url,则把所有invoker整合为RegistryAwareClusterInvoker,该Invoker在调用时,会查看所有Invoker中是否有默认的,如果有则使用默认的Invoker,如果没有,则使用第一个Invoker
                // 2. 如果这多个urls中不存在注册中心url,则把所有invoker整合为FailoverCluster

                List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
                URL registryURL = null; // 用来记录urls中最后一个注册中心url
                for (URL url : urls) {
    
    
                    invokers.add(REF_PROTOCOL.refer(interfaceClass, url));

                    if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
    
    
                        registryURL = url; // use last registry url
                    }
                }

                // 如果存在注册中心地址
                if (registryURL != null) {
    
     // registry url is available
                    // use RegistryAwareCluster only when register's CLUSTER is available
                    URL u = registryURL.addParameter(CLUSTER_KEY, RegistryAwareCluster.NAME);
                    // StaticDirectory表示静态服务目录,里面的invokers是不会变的, 生成一个RegistryAwareCluster
                    // The invoker wrap relation would be: RegistryAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, will execute route) -> Invoker
                    invoker = CLUSTER.join(new StaticDirectory(u, invokers));
                } else {
    
     // not a registry url, must be direct invoke.
                    // 如果不存在注册中心地址, 生成一个FailoverClusterInvoker
                    invoker = CLUSTER.join(new StaticDirectory(invokers));
                }
            }
        }
        return (T) PROXY_FACTORY.getProxy(invoker);
    }

  1. First, it will judge whether there is only one URL according to the configured urls
  2. If there is only one, then directly call REF_PROTOCOL.refer(interfaceClass, urls.get(0)) to create an Invoker, call the proxy factory to return the proxy instance, and the return is a FailoverClusterInvoker instance invoker;
  3. If there are multiple URLs, call REF_PROTOCOL.refer(interfaceClass, urls.get(0)) for each URL to create an Invoker instance;
    then determine whether there is a registry URL
    3.1, set the CLUSTER_KEY of the URL to registryaware, and then call CLUSTER. The join(new StaticDirectory(u, invokers)) method, through the SPI mechanism, calls to generate a RegistryAwareClusterInvoker instance invoker;
    3.2 does not exist, directly calls CLUSTER.join(new StaticDirectory(invokers)), and calls FailoverClusterInvoker through the SPI mechanism to generate a FailoverClusterInvoker instance invoker;

Call CLUSTER.join(new StaticDirectory(invokers)), because of the SPI mechanism, the Wrapper class will be called first;

When there are multiple URLs, there is a registration center, the first layer: MockClusterWrapper#join

The function of this class is Mock request processing;
call the join method

  • Call this.cluster.join(directory) to generate an Invoker instance and return it as a construction parameter of MockClusterInvoker,
  • Generate a MockClusterInvoker instance invoker;
  • That is, the outermost Invoker type is the MockClusterInvoker type
public class MockClusterWrapper implements Cluster {
    
    
    private Cluster cluster;
    @Override
    public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
    
    
        return new MockClusterInvoker<T>(directory,
                this.cluster.join(directory));
    }

}

In the case of multiple URLs, there is a registry, the second layer: RegistryAwareClusterInvoker#join

Call the join method to generate a RegistryAwareClusterInvoker instance;

public class RegistryAwareCluster implements Cluster {
    
    
    public final static String NAME = "registryaware";
    @Override
    public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
    
    
        return new RegistryAwareClusterInvoker<T>(directory);
    }
}

In the case of multiple URLs, there is a registration center, the third layer: FailoverClusterInvoker#join

No matter it is the 1st step of ReferenceConfigde#get() or the 3.1 step, an Invoker instance of FailoverClusterInvoker will be generated in the end; that is, the Invoker instance type finally generated by calling REF_PROTOCOL.refer(interfaceClass, url) is FailoverClusterInvoker

REF_PROTOCOL.refer(interfaceClass, url)

Through the SPI adaptive extension point technology, the first call is the refer method of the RegistryProtocol class;
call the doRefer method to generate an invoker instance;

  • Parameter cluster: represents the cluster fault-tolerant instance, the default is FailoverClusterInvoker;
  • registry : registration center address;
  • type : interface type;
  • url : the URL parameter of the service;
    @Override
    @SuppressWarnings("unchecked")
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    
    
        // url由 registry:// 改变为---> zookeeper://
        url = URLBuilder.from(url)
                .setProtocol(url.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY))
                .removeParameter(REGISTRY_KEY)
                .build();
        // 这里的cluster是cluster的Adaptive对象
        return doRefer(cluster, registry, type, url);
    }

private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
    
    
        // RegistryDirectory表示动态服务目录,会和注册中心的数据保持同步
        // type表示一个服务对应一个RegistryDirectory,url表示注册中心地址
        // 在消费端,最核心的就是RegistryDirectory
        RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
        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;
    }

The same will call cluster#join to generate an instance, and also call the wrapper class Wrapper#join method, the wrapper class is MockClusterWrapper, and create a MockClusterInvoker instance; then call the FailoverCluster#join method, create a FailoverClusterInvoker instance, and pass in RegistryDirectory instance, RegistryDirectory internally encapsulates an internal DelegateInvoker property;

The relationship between the painting layer and the layer is as follows

insert image description here

    private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
    
    
        RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);

        directory.subscribe(subscribeUrl.addParameter(CATEGORY_KEY,
                PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY));
        // 利用传进来的cluster,join得到invoker,
        Invoker invoker = cluster.join(directory);
        return invoker;
    }

RegistryDirectory#subscribe

The role of subscribing to the monitoring directory;

  • Call the registry#subscribe method to complete the subscription;
  • If the Zookeeper registry is used, the type of registry is ZookeeperRegistry, the subscribe method is not defined in the class, and the subscribe method is defined in the inherited FallbackRegistry class;
    public void subscribe(URL url) {
    
    
        setConsumerUrl(url);
        CONSUMER_CONFIGURATION_LISTENER.addNotifyListener(this); // 监听consumer应用
        serviceConfigurationListener = new ReferenceConfigurationListener(this, url); // 监听所引入的服务的动态配置
        registry.subscribe(url, this);
    }

FailbackRegistry#subscribe

  1. FailbackRegistry#subscribe calls the doSubscribe method, implemented by subclasses, simple factory pattern;
  2. The notify method is called in the ZookeeperRegistry#doSubscribe method, and the notify method is defined in the parent class
  3. The notify method of the parent class AbstractRegistry is called in FallbackRegistry#notify;
  4. AbstractRegistry calls the listener#notify method again; the listener type is RegistryDirectory
  5. The refreshOverrideAndInvoker method is called in the RegistryDirectory#notify method;
  6. RegistryDirectory#refreshOverrideAndInvoker calls the refreshInvoker method

public class FailbackRegistry extends AbstractRegistry {
    
    
	 @Override
    public void subscribe(URL url, NotifyListener listener) {
    
    
        super.subscribe(url, listener);
        try {
    
    
            // Sending a subscription request to the server side
            doSubscribe(url, listener);
        } catch (Exception e) {
    
    
         //省略代码
        }
  	  }
  	  
      protected void notify(URL url, NotifyListener listener, List<URL> urls) {
    
    
        try {
    
    
            doNotify(url, listener, urls);
        } catch (Exception t) {
    
    
        }
    }
    //super#notify调用AbstractRegistry#notify方法;
    protected void doNotify(URL url, NotifyListener listener, List<URL> urls) {
    
    
        super.notify(url, listener, urls);
    }
}
//notify方法在父类中定义了, 父类FailbackRegistry 的notify方法中
public class ZookeeperRegistry extends FailbackRegistry {
    
    
    @Override
    public void doSubscribe(final URL url, final NotifyListener listener) {
    
    
        try {
    
    
            if (ANY_VALUE.equals(url.getServiceInterface())) {
    
    
              //省略部分代码
            } else {
    
     //省略部分代码
	            // 单独订阅某一个服务;
                notify(url, listener, urls);
            }
        } catch (Throwable e) {
    
    
        }
    }
}

public class FailbackRegistry extends AbstractRegistry {
    
    
    protected void notify(URL url, NotifyListener listener, List<URL> urls) {
    
    

        for (Map.Entry<String, List<URL>> entry : result.entrySet()) {
    
    
            listener.notify(categoryList);
        }
    }

}

public class RegistryDirectory<T> extends AbstractDirectory<T> implements NotifyListener {
    
    
   @Override
    public synchronized void notify(List<URL> urls) {
    
    
        Map<String, List<URL>> categoryUrls = urls.stream()
                .filter(Objects::nonNull)
                .filter(this::isValidCategory)
                .filter(this::isNotCompatibleFor26x)
                .collect(Collectors.groupingBy(url -> {
    
    
                    if (UrlUtils.isConfigurator(url)) {
    
    
                        return CONFIGURATORS_CATEGORY;
                    } else if (UrlUtils.isRoute(url)) {
    
    
                        return ROUTERS_CATEGORY;
                    } else if (UrlUtils.isProvider(url)) {
    
    
                        return PROVIDERS_CATEGORY;
                    }
                    return "";
                }));
        // 获取服务提供者URL
        List<URL> providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY, Collections.emptyList());
        refreshOverrideAndInvoker(providerURLs);
    }

    private void refreshOverrideAndInvoker(List<URL> urls) {
    
    
        refreshInvoker(urls);
    }
 }

RegistryDirectory#refreshInvoker

  1. will call toInvokers to generate an Invoker for each URL;
  2. Assign a value to the custom invokers property
public class RegistryDirectory<T> extends AbstractDirectory<T> implements NotifyListener {
    
    
private void refreshInvoker(List<URL> invokerUrls) {
    
    
        if (invokerUrls.size() == 1 && invokerUrls.get(0) != null && EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {
    
    
        } else {
    
    
            // 这里会先按Protocol进行过滤,并且调用DubboProtocol.refer方法得到DubboInvoker
            Map<String, Invoker<T>> newUrlInvokerMap = toInvokers(invokerUrls);// Translate url list to Invoker map
			//给自定的invokers属性赋值;
            this.invokers = multiGroup ? toMergeInvokerList(newInvokers) : newInvokers;
            this.urlInvokerMap = newUrlInvokerMap;
			//省略部分代码;
        }
    }

}

The fourth layer: RegistryDirectory$InvokerDelegate

toInvokers,

  1. An instance of the inner class InvokerDelegate will be created;
  2. When calling protocol#refer, the DubboProtocol#refer method will be called for processing; due to the SPI mechanism, the wrapper class Wrapper will be called first for processing;
public class RegistryDirectory<T> extends AbstractDirectory<T> implements NotifyListener {
    
    
private Map<String, Invoker<T>> toInvokers(List<URL> urls) {
    
    
        for (URL providerUrl : urls) {
    
    
            if (invoker == null) {
    
     // Not in the cache, refer again
                try {
    
    
                    if (enabled) {
    
    
                        // 调用Protocol的refer方法得到一个Invoker
                        invoker = new InvokerDelegate<>(protocol.refer(serviceType, url), url, providerUrl);   }
                } catch (Throwable t) {
    
    }
            } else {
    
    
            }
        }
        return newUrlInvokerMap;
    }
}

The fifth layer: ListenerInvokerWrapper

protocol.refer(type, url) returns an Invoker, as a parameter, creates a ListenerInvokerWrapper instance;

public class ProtocolListenerWrapper implements Protocol {
    
    
 @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    
    
        if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
    
    
            return protocol.refer(type, url);
        }
        return new ListenerInvokerWrapper<T>(protocol.refer(type, url),
                Collections.unmodifiableList(
                        ExtensionLoader.getExtensionLoader(InvokerListener.class)
                                .getActivateExtension(url, INVOKER_LISTENER_KEY)));
    }


}

protocol.refer(type, url) The next layer calls the ProtocolFilterWrapper#refer method;

The sixth layer: CallbackRegistrationInvoker

  • After calling buildInvokerChain, a CallbackRegistrationInvoker instance is returned; therefore, the fifth layer is CallbackRegistrationInvoker;
  • In the buildInvokerChain method, a filter processing chain is generated;
  • protocol.refer(type, url) : return Invoker instance ;
  • REFERENCE_FILTER_KEY : The value is reference.filter
  • CommonConstants.CONSUMER : 值为consumer

Work:

  1. According to the key and value, all Filters with the group name consumer will be obtained;
  2. Create a corresponding Invoker instance for each Filter;
  3. Finally, the Invoker instance corresponding to the outermost Filter is used as a parameter to create a CallbackRegistrationInvoker instance;
public class ProtocolFilterWrapper implements Protocol {
    
    
    @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    
    
        if (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
    
    
            return protocol.refer(type, url);
        }
        return buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);
    }
    
    private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    
    
        Invoker<T> last = invoker;
        // 根据url获取filter,根据url中的parameters取key为key的value所对应的filter,但是还会匹配group
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
        if (!filters.isEmpty()) {
    
    
            for (int i = filters.size() - 1; i >= 0; i--) {
    
    
                final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {
    
    
                    @Override
                    public Result invoke(Invocation invocation) throws RpcException {
    
    
                        Result asyncResult;
                        try {
    
    
                            // 得到一个异步结果
                            asyncResult = filter.invoke(next, invocation);
                        } catch (Exception e) {
    
    
                        }
                        return asyncResult;
                    }
                };
            }
        }
        return new CallbackRegistrationInvoker<>(last, filters);
    }
}

Client Filter calling order

dubbo-rpc-api module

genericimpl=org.apache.dubbo.rpc.filter.GenericImplFilter  //order+20000
activelimit=org.apache.dubbo.rpc.filter.ActiveLimitFilter  // order无
consumercontext=org.apache.dubbo.rpc.filter.ConsumerContextFilter //order = -10000

dubbo-monitor-api module

monitor=org.apache.dubbo.monitor.support.MonitorFilter

dubbo-rpc-dubbo module

future=org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter

The calling sequence is:

  1. ConsumerContextFilter#invoke
  2. FutureFilter#invoke
  3. MonitorFilter#invoke

After MonitorFilter#refer is called, the filter chain Invoker is generated;

In the ProtocolFilterWrapper#refer method, the first parameter to call buildInvokerChain is: protocol.refer(type, url), that is, the next Protocol calls the DubboProtocol#refer method

AbstractProtocol#refer

Refer is not defined in DubboProtocol, which inherits the AbstractProtocol class, and the refer method is defined in AbstractProtocol;

Seventh layer: AsyncToSyncInvoker

The role of this class: Convert asynchronous requests to synchronous requests, this class Invoker is very important

  • The protocolBindingRefer(type, url) method returns an Invoker instance as a parameter and creates an AsyncToSyncInvoker instance;
  • protocolBindingRefer is an abstract method implemented by subclasses, here is DubboProtocol
public abstract class AbstractProtocol implements Protocol {
    
    
 @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    
    
        // 异步转同步Invoker , type是接口,url是服务地址
        // DubboInvoker是异步的,而AsyncToSyncInvoker会封装为同步的
        return new AsyncToSyncInvoker<>(protocolBindingRefer(type, url));
    }

    protected abstract <T> Invoker<T> protocolBindingRefer(Class<T> type, URL url) throws RpcException;
}

DubboProtocol#protocolBindingRefer

Ninth layer: DubboInvoker

In the protocolBindingRefer method, a DubboInvoker instance is created and returned;

    @Override
    public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {
    
    
        // 在DubboInvoker发送请求时会轮询clients去发送数据
        DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
        invokers.add(invoker);

        return invoker;
    }

So far, the number of packaging layers of Invoker has a total of 9 layers; if you look closely, you need to add the Invoker corresponding to the filter filter:

The final graph is as follows:
insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/yaoyaochengxian/article/details/124540740