SpringCloud Alibaba系列——8Dubbo的服务发现

老老老JR老北
发布于 2022-8-24 16:35
浏览
0收藏

作者 | 一起撸Java
来源 |今日头条

学习目标

  1. Dubbo的服务发现
    第1章 注册发现
    同样的先贴出总体流程图

SpringCloud Alibaba系列——8Dubbo的服务发现-鸿蒙开发者社区1.1 spring代理对象
当你用@DubboReference标识一个属性时,其实spring会生成了spring的代理对象注入进去。spring创建代理的过程在上节课的时候我们已经讲过,同学们可以翻看上节课的笔记看看代理的生成原理。

private void createLazyProxy() {    //set proxy interfaces    //see also:org.apache.dubbo.rpc.proxy.AbstractProxyFactory.getProxy(org.apache.dubbo.rpc.Invoker<T>,boolean)    //很明显这里会用spring的代理工厂生成代理对象    ProxyFactory proxyFactory = new ProxyFactory();    //定义哦了TargetSource类型实例,spring中会有该类调用其getTarget方法拿到目标对象,其实这里就会生成Dubbo的代理    proxyFactory.setTargetSource(new DubboReferenceLazyInitTargetSource());    proxyFactory.addInterface(interfaceClass);    Class<?>[] internalInterfaces = AbstractProxyFactory.getInternalInterfaces();    for (Class<?> anInterface : internalInterfaces) {        proxyFactory.addInterface(anInterface);    }    if (!StringUtils.isEquals(interfaceClass.getName(), interfaceName)) {        //add service interface        try {            Class<?> serviceInterface = ClassUtils.forName(interfaceName, beanClassLoader);            proxyFactory.addInterface(serviceInterface);        } catch (ClassNotFoundException e) {            // generic call maybe without service interface class locally        }    }    //返回spring的代理    this.lazyProxy = proxyFactory.getProxy(this.beanClassLoader);}

在spring中的JDKDynamicAopProxy类中就会回调TargetSource对象的getTarget方法,在getTarget方法中生成了dubbo的代理对象。

private class DubboReferenceLazyInitTargetSource extends AbstractLazyCreationTargetSource {    @Override    protected Object createObject() throws Exception {        return getCallProxy();    }    @Override    public synchronized Class<?> getTargetClass() {        return getInterfaceClass();    }}//父类的getTarget方法会被spring的advice调用到,又会回调子类的createObject方法,模板设计模式@Overridepublic synchronized Object getTarget() throws Exception {    if (this.lazyTarget == null) {        logger.debug("Initializing lazy target object");        this.lazyTarget = createObject();    }    return this.lazyTarget;}
private Object getCallProxy() throws Exception {    if (referenceConfig == null) {        throw new IllegalStateException("ReferenceBean is not ready yet, please make sure to call reference interface method after dubbo is started.");    }    //获取引用代理    //get reference proxy    return referenceConfig.get();}

从源码中可以看到,最终服务的引用还是调到了referenceConfig.get()方法,那我们就来看看get方法是如何走的。

1.2 dubbo代理对象
前面我们知道,当我们用spring的代理对象调用的时候,最终会走到JDKDynamicAopProxy类中的invoke方法,然后调用getTarget方法生成了一个dubbo的代理对象,那么这个代理对象是如何生成的呢?我们看看生成dubbo代理对象的核心代码;

private T createProxy(Map<String, String> map) {    //是不是injvm调用    if (shouldJvmRefer(map)) {        URL url = new ServiceConfigURL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0,interfaceClass.getName()).addParameters(map);        invoker = REF_PROTOCOL.refer(interfaceClass, url);        if (logger.isInfoEnabled()) {            logger.info("Using injvm service " + interfaceClass.getName());        }    } else {        urls.clear();        if (url != null && url.length() > 0) {             // user specified URL, could be peer-to-peer address, or register center's address.            String[] us = SEMICOLON_SPLIT_PATTERN.split(url);            if (us != null && us.length > 0) {                for (String u : us) {                    URL url = URL.valueOf(u);                    if (StringUtils.isEmpty(url.getPath())) {                        url = url.setPath(interfaceName);                    }                    if (UrlUtils.isRegistry(url)) {                        urls.add(url.putAttribute(REFER_KEY, map));                    } else {                        URL peerURL = ClusterUtils.mergeUrl(url, map);                        peerURL = peerURL.putAttribute(PEER_KEY, true);                        urls.add(peerURL);                    }                }            }        } else { // assemble URL from register center's configuration            // if protocols not injvm checkRegistry            //如果协议不是injvm            if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) {                checkRegistry();                List<URL> us = ConfigValidationUtils.loadRegistries(this, false);                if (CollectionUtils.isNotEmpty(us)) {                    for (URL u : us) {                        URL monitorUrl = ConfigValidationUtils.loadMonitor(this, u);                        if (monitorUrl != null) {                            u = u.putAttribute(MONITOR_KEY, monitorUrl);                        }                        urls.add(u.putAttribute(REFER_KEY, 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.");                }            }        }        if (urls.size() == 1) {            //生成MigrationInvoker对象,走包装类            invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));        } else {            List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();            URL registryURL = null;            for (URL url : urls) {                // For multi-registry scenarios, it is not checked whether each referInvoker is available.                // Because this invoker may become available later.                invokers.add(REF_PROTOCOL.refer(interfaceClass, url));                if (UrlUtils.isRegistry(url)) {                    registryURL = url; // use last registry url                }            }            if (registryURL != null) { // registry url is available                // for multi-subscription scenario, use 'zone-aware' policy by default                String cluster = registryURL.getParameter(CLUSTER_KEY,ZoneAwareCluster.NAME);                // The invoker wrap sequence would be:ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory,routing happens here) -> Invoker                invoker = Cluster.getCluster(cluster, false).join(new StaticDirectory(registryURL, invokers));            } else { // not a registry url, must be direct invoke.                String cluster = CollectionUtils.isNotEmpty(invokers) ? (invokers.get(0).getUrl() != null ? invokers.get(0).getUrl().getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME) : Cluster.DEFAULT) : Cluster.DEFAULT;                invoker = Cluster.getCluster(cluster).join(new StaticDirectory(invokers));            }        }    }    if (logger.isInfoEnabled()) {        logger.info("Referred dubbo service " + interfaceClass.getName());    }    URL consumerURL = new ServiceConfigURL(CONSUMER_PROTOCOL, map.get(REGISTER_IP_KEY), 0,map.get(INTERFACE_KEY), map);    MetadataUtils.publishServiceDefinition(consumerURL);    //生成代理对象    // create service proxy    return (T) PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic));}

从代码来看看,其实在生成dubbo代理之前想要生成invoker对象,因为代理对象也要通过invoker来完成服务的远程调用的。所以我们先看看生成invoker的逻辑。

1.2.1 invoker对象的生成
1.2.1.1描述
当我们用dubbo的代理对象进行调用的时候,实际上代理对象的advice一样是持有了invoker对象的引用的,实际上是用invoker对象进行后续逻辑的调用,所以我们第一步是要获取到进行rpc远程调用的invoker对象。

1.2.1.2源码分析
源码是 invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));,根据protocol对象调用refer方法获取到invoker对象,这里获取到的invoker对象是MigrationInvoker对象。其实refer流程跟之前分析的export流程有点类似,也是先走registry协议完成consumer的注册,然后在dubbo协议中开启了netty客户端的连接的。那么我们就一个个的分析

1、包装类的流转

registry协议对应的包装类的流转

  • QosProtocolWrapper。一样的是开启qos服务
    @Overridepublic <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {    if (UrlUtils.isRegistry(url)) {        startQosServer(url);        return protocol.refer(type, url);    }    return protocol.refer(type, url);}​
  • ProtocolSerializationWrapper
    @Overridepublic <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {    return protocol.refer(type, url);}​
  • ProtocolFilterWrapper
    @Overridepublic <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {    if (UrlUtils.isRegistry(url)) {        return protocol.refer(type, url);    }    return builder.buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY,                                     CommonConstants.CONSUMER);}​
  • ProtocolListenerWrapper
@Overridepublic <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {    if (UrlUtils.isRegistry(url)) {        return protocol.refer(type, url);    }    Invoker<T> invoker = protocol.refer(type, url);    if (StringUtils.isEmpty(url.getParameter(REGISTRY_CLUSTER_TYPE_KEY))) {        invoker = new ListenerInvokerWrapper<>(invoker,                                               Collections.unmodifiableList(                                                   ExtensionLoader.getExtensionLoader(InvokerListener.class)                                                   .getActivateExtension(url, INVOKER_LISTENER_KEY)));    }    return invoker;}​

 

2、InterfaceCompatibleRegistryProtocol

在这里完成了消费者注册流程

@Override@SuppressWarnings("unchecked")public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {    //根据url获取注册的协议地址 zookeeper://xxx    url = getRegistryUrl(url);    //根据协议头获取注册逻辑类    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 = (Map<String, String>) url.getAttribute(REFER_KEY);    String group = qs.get(GROUP_KEY);    if (group != null && group.length() > 0) {        if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {            return doRefer(Cluster.getCluster(MergeableCluster.NAME), registry, type, url,qs);        }    }    //获取集群容错对象 默认是FailoverCluster    Cluster cluster = Cluster.getCluster(qs.get(CLUSTER_KEY));    return doRefer(cluster, registry, type, url, qs);}
protected <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL                                 url, Map<String, String> parameters) {    Map<String, Object> consumerAttribute = new HashMap<>(url.getAttributes());    consumerAttribute.remove(REFER_KEY);    URL consumerUrl = new ServiceConfigURL(parameters.get(PROTOCOL_KEY) == null ? DUBBO :                                           parameters.get(PROTOCOL_KEY),                                           null,                                           null,                                           parameters.get(REGISTER_IP_KEY),                                           0, getPath(parameters, type),                                           parameters,                                           consumerAttribute);    url = url.putAttribute(CONSUMER_URL_KEY, consumerUrl);    //获取 MigrationInvoker对象    ClusterInvoker<T> migrationInvoker = getMigrationInvoker(this, cluster, registry, type,url, consumerUrl);    return interceptInvoker(migrationInvoker, url, consumerUrl, url);}
protected <T> Invoker<T> interceptInvoker(ClusterInvoker<T> invoker, URL url, URL                                          consumerUrl, URL registryURL) {    //获取 MigrationRuleListener 监听类    List<RegistryProtocolListener> listeners = findRegistryProtocolListeners(url);    if (CollectionUtils.isEmpty(listeners)) {        return invoker;    }    for (RegistryProtocolListener listener : listeners) {        //调用MigrationRuleListener的 onRefer方法        listener.onRefer(this, invoker, consumerUrl, registryURL);    }    return invoker;}
@Overridepublic void onRefer(RegistryProtocol registryProtocol, ClusterInvoker<?> invoker, URL                    consumerUrl, URL registryURL) {    MigrationRuleHandler<?> migrationRuleHandler =        handlers.computeIfAbsent((MigrationInvoker<?>) invoker, _key -> {            ((MigrationInvoker<?>) invoker).setMigrationRuleListener(this);            return new MigrationRuleHandler<>((MigrationInvoker<?>) invoker, consumerUrl);        });    //迁移规则的处理器    migrationRuleHandler.doMigrate(rule);}
public synchronized void doMigrate(MigrationRule rule) {    if (migrationInvoker instanceof ServiceDiscoveryMigrationInvoker) {        refreshInvoker(MigrationStep.FORCE_APPLICATION, 1.0f, rule);        return;    }    // initial step : APPLICATION_FIRST    MigrationStep step = MigrationStep.APPLICATION_FIRST;    float threshold = -1f;    try {        step = rule.getStep(consumerURL);        threshold = rule.getThreshold(consumerURL);    } catch (Exception e) {        logger.error("Failed to get step and threshold info from rule: " + rule, e);    }    //核心代码    if (refreshInvoker(step, threshold, rule)) {        // refresh success, update rule        setMigrationRule(rule);    }}
@Overridepublic void migrateToApplicationFirstInvoker(MigrationRule newRule) {    CountDownLatch latch = new CountDownLatch(0);    //RegistryDirectory 主要看这里    refreshInterfaceInvoker(latch);    //ServiceDiscoveryRegistryDirectory    refreshServiceDiscoveryInvoker(latch);    // directly calculate preferred invoker, will not wait until address notify    // calculation will re-occurred when address notify later    calcPreferredInvoker(newRule);}
protected void refreshInterfaceInvoker(CountDownLatch latch) {    clearListener(invoker);    if (needRefresh(invoker)) {        if (logger.isDebugEnabled()) {            logger.debug("Re-subscribing interface addresses for interface " + type.getName());        }        if (invoker != null) {            invoker.destroy();        }        //获取 invoker对象。。在这里真正获取到了一个invoker对象被MigrationInvoker持有        invoker = registryProtocol.getInvoker(cluster, registry, type, url);    }    setListener(invoker, () -> {        latch.countDown();        FrameworkStatusReporter.reportConsumptionStatus(            createConsumptionReport(consumerUrl.getServiceInterface(),consumerUrl.getVersion(), consumerUrl.getGroup(), "interface")        );        if (step == APPLICATION_FIRST) {            calcPreferredInvoker(rule);        }    });}

RegistryDirectory这个类是一个非常关键的类,该类中有整个客户端的服务列表,并且在这个类中有很多事件监听,可以监听到数据的变更然后刷新本地服务列表。

@Overridepublic <T> ClusterInvoker<T> getInvoker(Cluster cluster, Registry registry, Class<T> type,URL url) {    DynamicDirectory<T> directory = new RegistryDirectory<>(type, url);    return doCreateInvoker(directory, cluster, registry, type);}
protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster                                                cluster, Registry registry, Class<T> type) {    directory.setRegistry(registry);    directory.setProtocol(protocol);    // all attributes of REFER_KEY    Map<String, String> parameters = new HashMap<String, String>        (directory.getConsumerUrl().getParameters());    URL urlToRegistry = new ServiceConfigURL(        parameters.get(PROTOCOL_KEY) == null ? DUBBO : parameters.get(PROTOCOL_KEY),        parameters.remove(REGISTER_IP_KEY), 0, getPath(parameters, type), parameters);    if (directory.isShouldRegister()) {        directory.setRegisteredConsumerUrl(urlToRegistry);        //把协议注册到 /dubbo/com.example.userService/consumers节点下面        registry.register(directory.getRegisteredConsumerUrl());    }    //创建路由链    directory.buildRouterChain(urlToRegistry);    //订阅事件,对 configurations,providers,routes节点建立监听    directory.subscribe(toSubscribeUrl(urlToRegistry));    //返回默认的 FailoverClusterInvoker对象    return (ClusterInvoker<T>) cluster.join(directory);}

1.2.1.3 总结
从上面源码分析看到了,最终返回了一个invoker对象,invoker对象关系是:MigrationInvoker->MockClusterInvoker->FailoverClusterInvoker

1.2.2 dubbo生成代理对象
前面我们分析到了通过protocol.refer方法调用已经生成了一个invoker对象了,现在这个invoker要传递给一个代理对象,看看代理对象是如何生成的。

PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic));

根据SPI的规则,首先经过包装类
StubProxyFactoryWrapper.getProxy方法:

@Overridepublic <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {    T proxy = proxyFactory.getProxy(invoker, generic);    if (GenericService.class != invoker.getInterface()) {        URL url = invoker.getUrl();        String stub = url.getParameter(STUB_KEY, url.getParameter(LOCAL_KEY));        if (ConfigUtils.isNotEmpty(stub)) {            Class<?> serviceType = invoker.getInterface();            if (ConfigUtils.isDefault(stub)) {                if (url.hasParameter(STUB_KEY)) {                    stub = serviceType.getName() + "Stub";                } else {                    stub = serviceType.getName() + "Local";                }            }            try {                Class<?> stubClass = ReflectUtils.forName(stub);                if (!serviceType.isAssignableFrom(stubClass)) {                    throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + serviceType.getName());                }                try {                    Constructor<?> constructor = ReflectUtils.findConstructor(stubClass,serviceType);                    proxy = (T) constructor.newInstance(new Object[]{proxy});                    //export stub service                    URLBuilder urlBuilder = URLBuilder.from(url);                    if (url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT)) {                        urlBuilder.addParameter(STUB_EVENT_METHODS_KEY,StringUtils.join(Wrapper.getWrapper(proxy.getClass()).getDeclaredMethodNames(), ","));                        urlBuilder.addParameter(IS_SERVER_KEY, Boolean.FALSE.toString());                        try {                            export(proxy, (Class) invoker.getInterface(),urlBuilder.build());                        } catch (Exception e) {                            LOGGER.error("export a stub service error.", e);                        }                    }                } catch (NoSuchMethodException e) {                    throw new IllegalStateException("No such constructor \"public " + stubClass.getSimpleName() + "(" + serviceType.getName() + ")\" in stub implementation class" + stubClass.getName(), e);                }            } catch (Throwable t) {                LOGGER.error("Failed to create stub implementation class " + stub + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ",cause: " + t.getMessage(), t);                // ignore            }        }    }    return proxy;}

然后包装类调到JavassistProxyFactory

@Overridepublic <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {    // when compiling with native image, ensure that the order of the interfaces remains unchanged    LinkedHashSet<Class<?>> interfaces = new LinkedHashSet<>();    String config = invoker.getUrl().getParameter(INTERFACES);    if (config != null && config.length() > 0) {        String[] types = COMMA_SPLIT_PATTERN.split(config);        for (String type : types) {            // TODO can we load successfully for a different classloader?.            interfaces.add(ReflectUtils.forName(type));        }    }    if (generic) {        if (GenericService.class.equals(invoker.getInterface()) || !GenericService.class.isAssignableFrom(invoker.getInterface())) {            interfaces.add(com.alibaba.dubbo.rpc.service.GenericService.class);        }        try {            // find the real interface from url            String realInterface = invoker.getUrl().getParameter(Constants.INTERFACE);            interfaces.add(ReflectUtils.forName(realInterface));        } catch (Throwable e) {            // ignore        }    }    interfaces.add(invoker.getInterface());    interfaces.addAll(Arrays.asList(INTERNAL_INTERFACES));    //生成代理对象    return getProxy(invoker, interfaces.toArray(new Class<?>[0]));}
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {    return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));}

从上述代码中可以看到,最终dubbo生成了一个jdk的动态代理类,当spring的JDKDynamicAopProxy中持有该对象调用方法时,最终代码逻辑会走到InvokerInvocationHandler类的invoke方法,InvokerInvocationHandler持有了通过protocol.refer方法创建的invoker对象,该invoker对象是可以通过rpc远程访问的。

1.2.3 RegistryDirectory服务列表的刷新
在调用过程中我们需要获取到一个调用的服务列表,而这个服务列表是由RegistryDirectory提供的,那么服务列表是如何有值的呢?

RegistryDirectory类是实现了NotifyListener接口的,最终会被zookeeper的事件回调到NotifyListener接口的notify方法,这个为什么会这样我们后续会讲到。

我们看看RegistryDirectory中的notify方法:

//事件监听回调@Overridepublic synchronized void notify(List<URL> urls) {    if (isDestroyed()) {        return;    }    //对回调的协议分组    // routes://    // override://    //dubbo://    Map<String, List<URL>> categoryUrls = urls.stream()        .filter(Objects::nonNull)        .filter(this::isValidCategory)        .filter(this::isNotCompatibleFor26x)        .collect(Collectors.groupingBy(this::judgeCategory));    List<URL> configuratorURLs = categoryUrls.getOrDefault(CONFIGURATORS_CATEGORY,Collections.emptyList());    this.configurators = Configurator.toConfigurators(configuratorURLs).orElse(this.configurators);    List<URL> routerURLs = categoryUrls.getOrDefault(ROUTERS_CATEGORY,Collections.emptyList());    //生成路由规则,加入到规则链中    toRouters(routerURLs).ifPresent(this::addRouters);    // providers    List<URL> providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY,Collections.emptyList());    /**  * 3.x added for extend URL address  */    ExtensionLoader<AddressListener> addressListenerExtensionLoader = ExtensionLoader.getExtensionLoader(AddressListener.class);    List<AddressListener> supportedListeners = addressListenerExtensionLoader.getActivateExtension(getUrl(), (String[]) null);    if (supportedListeners != null && !supportedListeners.isEmpty()) {        for (AddressListener addressListener : supportedListeners) {            providerURLs = addressListener.notify(providerURLs, getConsumerUrl(),this);        }    }    //刷新本地服务列表    refreshOverrideAndInvoker(providerURLs);}

刷新本地服务列表

//刷新本地服务列表private void refreshInvoker(List<URL> invokerUrls) {    Assert.notNull(invokerUrls, "invokerUrls should not be null");    if (invokerUrls.size() == 1        && invokerUrls.get(0) != null        && EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {        this.forbidden = true; // Forbid to access        this.invokers = Collections.emptyList();        routerChain.setInvokers(this.invokers);        destroyAllInvokers(); // Close all invokers    } else {        this.forbidden = false; // Allow to access        Map<URL, Invoker<T>> oldUrlInvokerMap = this.urlInvokerMap; // local reference        if (invokerUrls == Collections.<URL>emptyList()) {            invokerUrls = new ArrayList<>();        }        if (invokerUrls.isEmpty() && this.cachedInvokerUrls != null) {            invokerUrls.addAll(this.cachedInvokerUrls);        } else {            this.cachedInvokerUrls = new HashSet<>();            this.cachedInvokerUrls.addAll(invokerUrls);//Cached invoker urls, convenient for comparison        }        if (invokerUrls.isEmpty()) {            return;        }        //创建url和invoker对象的映射关系 .这里会根据dubbo协议创建invoker读写        Map<URL, Invoker<T>> newUrlInvokerMap = toInvokers(invokerUrls);// Translate url list to Invoker map        /**    * If the calculation is wrong, it is not processed.    *    * 1. The protocol configured by the client is inconsistent with the protocol of the server.    *  eg: consumer protocol = dubbo, provider only has other protocol services(rest).    * 2. The registration center is not robust and pushes illegal specification data.    *    */        if (CollectionUtils.isEmptyMap(newUrlInvokerMap)) {            logger.error(new IllegalStateException("urls to invokers error                                                   .invokerUrls.size :" + invokerUrls.size() + ", invoker.size :0. urls :" + invokerUrls                                                   .toString()));            return;        }        //所有的invoker对象        List<Invoker<T>> newInvokers = Collections.unmodifiableList(new ArrayList<>                                                                    (newUrlInvokerMap.values()));        // pre-route and build cache, notice that route cache should build on original Invoker list.        // toMergeMethodInvokerMap() will wrap some invokers having different groups, those wrapped invokers not should be routed.        routerChain.setInvokers(newInvokers);        //这个invokers就是我们的服务列表        this.invokers = multiGroup ? toMergeInvokerList(newInvokers) : newInvokers;        this.urlInvokerMap = newUrlInvokerMap;        try {            destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); // Close the unused Invoker        } catch (Exception e) {            logger.warn("destroyUnusedInvokers error. ", e);        }        // notify invokers refreshed        this.invokersChanged();    }}

1.2.4 服务列表invoker的生成
前面我们在刷新服务列表的notify方法中我们看到了

Map<URL, Invoker> newUrlInvokerMap = toInvokers(invokerUrls);方法,其实所有的DubboInvoker对象都是在这里生成的,netty客户端的启动,调用链handler的建立都是在这里。

private Map<URL, Invoker<T>> toInvokers(List<URL> urls) {    Map<URL, Invoker<T>> newUrlInvokerMap = new ConcurrentHashMap<>();    if (urls == null || urls.isEmpty()) {        return newUrlInvokerMap;    }    String queryProtocols = this.queryMap.get(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 (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;        }        URL url = mergeUrl(providerUrl);        // 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<URL, Invoker<T>> localUrlInvokerMap = this.urlInvokerMap; // local reference        Invoker<T> invoker = localUrlInvokerMap == null ? null : localUrlInvokerMap.remove(url);        if (invoker == null) { // Not in the cache, refer again            try {                boolean enabled = true;                if (url.hasParameter(DISABLED_KEY)) {                    enabled = !url.getParameter(DISABLED_KEY, false);                } else {                    enabled = url.getParameter(ENABLED_KEY, true);                }                if (enabled) {                    //生成invoker对象 。。核心代码,这里的协议是dubbo协议。                    invoker = protocol.refer(serviceType, url);                }            } 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(url, invoker);            }        } else {            newUrlInvokerMap.put(url, invoker);        }    }    return newUrlInvokerMap;}

关键代码就是:

//生成invoker对象 。。核心代码,这里的协议是dubbo协议。 invoker = protocol.refer(serviceType, url);

前面我们分析过,跟export方法的逻辑有点类似:

1.2.4.1 包装类的流转
1、QosProtocolWrapper

@Overridepublic <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {    if (UrlUtils.isRegistry(url)) {        startQosServer(url);        return protocol.refer(type, url);    }    return protocol.refer(type, url);}

2、ProtocolSerializationWrapper

@Overridepublic <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {    return protocol.refer(type, url);}

3、ProtocolFilterWrapper

创建一个invoker的链,前面分析过,这里不赘述了

@Overridepublic <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {    if (UrlUtils.isRegistry(url)) {        return protocol.refer(type, url);    }    return builder.buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY,CommonConstants.CONSUMER);}

4、ProtocolListenerWrapper

服务引用后触发事件,前面分析过不赘述了。

@Overridepublic <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {    if (UrlUtils.isRegistry(url)) {        return protocol.refer(type, url);    }    Invoker<T> invoker = protocol.refer(type, url);    if (StringUtils.isEmpty(url.getParameter(REGISTRY_CLUSTER_TYPE_KEY))) {        invoker = new ListenerInvokerWrapper<>(invoker,                                               Collections.unmodifiableList(                                                   ExtensionLoader.getExtensionLoader(InvokerListener.class)                                                   .getActivateExtension(url, INVOKER_LISTENER_KEY)));    }    return invoker;}

1.2.4.2 DubboProtocol

在DubboProtocol中完成了netty客户端的连接,handler链路的调用,其实这块跟DubboProtocol中的服务发布过程的export方法很类似。核心代码在getClients方法中

@Overridepublic <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws    RpcException {    optimizeSerialization(url);    // create rpc invoker.    //创建用于远程调用的invoker对象 getClients(url)核心方法    DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url),invokers);    invokers.add(invoker);    return invoker;}
private ExchangeClient[] getClients(URL url) {    // whether to share connection    boolean useShareConnect = false;    int connections = url.getParameter(CONNECTIONS_KEY, 0);    List<ReferenceCountExchangeClient> shareClients = null;    // if not configured, connection is shared, otherwise, one connection for one service    if (connections == 0) {        useShareConnect = true;        /*    * The xml configuration should have a higher priority than properties.    */        String shareConnectionsStr = url.getParameter(SHARE_CONNECTIONS_KEY, (String) null);        //默认建立一个长连接        connections = Integer.parseInt(StringUtils.isBlank(shareConnectionsStr) ?ConfigUtils.getProperty(SHARE_CONNECTIONS_KEY,DEFAULT_SHARE_CONNECTIONS) : shareConnectionsStr);        shareClients = getSharedClient(url, connections);    }    ExchangeClient[] clients = new ExchangeClient[connections];    for (int i = 0; i < clients.length; i++) {        if (useShareConnect) {            clients[i] = shareClients.get(i);        } else {            //初始化客户端            clients[i] = initClient(url);        }    }    return clients;}
private ExchangeClient initClient(URL url) {    // client type setting.    String str = url.getParameter(CLIENT_KEY, url.getParameter(SERVER_KEY,DEFAULT_REMOTING_CLIENT));    url = url.addParameter(CODEC_KEY, DubboCodec.NAME);    // enable heartbeat by default    url = url.addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT));    // BIO is not allowed since it has severe performance issue.    if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {        throw new RpcException("Unsupported client type: " + str + "," + " supported client type is " + StringUtils.join(ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(), " "));    }    ExchangeClient client;    try {        // connection should be lazy        if (url.getParameter(LAZY_CONNECT_KEY, false)) {            client = new LazyConnectExchangeClient(url, requestHandler);        } else {            //核心代码,建立连接            client = Exchangers.connect(url, requestHandler);        }    } catch (RemotingException e) {        throw new RpcException("Fail to create remoting client for service(" + url + "): " + e.getMessage(), e);    }    return client;}
@Overridepublic ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {    return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);}
public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException{    if (url == null) {        throw new IllegalArgumentException("url == null");    }    ChannelHandler handler;    if (handlers == null || handlers.length == 0) {        handler = new ChannelHandlerAdapter();    } else if (handlers.length == 1) {        handler = handlers[0];    } else {        handler = new ChannelHandlerDispatcher(handlers);    }    return getTransporter().connect(url, handler);}
@Overridepublic Client connect(URL url, ChannelHandler handler) throws RemotingException {    return new NettyClient(url, handler);}

在NettyClient构造函数中又对handler进行了再一次包装,整个过程跟NettyServer类似我这里就不赘述了。

分类
已于2022-8-24 16:35:23修改
收藏
回复
举报
回复
    相关推荐