likes
comments
collection
share

Dubbo源码|二十一、Dubbo服务引入——创建代理对象

作者站长头像
站长
· 阅读数 16

开篇

本文介绍Dubbo服务引入部分的源码分析——创建代理对象。

Dubbo服务引入(一)

Dubbo服务引入(二)

创建代理

该方法的主要目的是,创建Invoker代理对象,创建代理对象的方法在ReferenceConfig#createProxy中。

private T createProxy(Map<String, String> map) {
    if (shouldJvmRefer(map)) {
        URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
    } else {
        // .....省略代码
        if (urls.size() == 1) {
            invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
        } else {
            List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
            URL registryURL = null;
            for (URL url : urls) {
                invokers.add(REF_PROTOCOL.refer(interfaceClass, url));
                if (UrlUtils.isRegistry(url)) {
                    registryURL = url; 
                }
            }
            if (registryURL != null) {
                String cluster = registryURL.getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME);
                invoker = Cluster.getCluster(cluster, false).join(new StaticDirectory(registryURL, invokers));
            } else {
                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));
            }
        }
    }
    URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);
    MetadataUtils.publishServiceDefinition(consumerURL);
    return (T) PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic));
}

该方法主要处理流程如下:

  1. 根据map判断是否为injvm引用, 如果是则使用injvm的服务。
  2. 如果@DubboReference注解中设置了url参数,则进行解析并将其放入urls中,url参数可以直接写服务提供者的地址,这样可以直接进行调用。
  3. 判断协议如果不是injvm协议,则进行检测注册中心,去除注册中心的URL并添加refer参数,并将url放入urls中。
  4. 判断urls的个数,如果只有一个,则直接调用REF_PROTOCOL.refer返回代理对象。
  5. 如果urls内有多个,则遍历每一个url,调用REF_PROTOCOL.refer生成代理对象。
  6. 判断是否存在注册中心URL配置。
  7. 如果存在,则把Invoker集合整合为ZoneAwareClusterInvoker
  8. 如果不存在,则把Invoker集合整合为FailoverClusterInvoker
  9. 构造consumerURL。
  10. 调用PROXY_FACTORY.getProxy方法,生成代理对象,其中PROXY_FACTORY是个代理工厂,默认使用的是javassist

refer

REF_PROTOCOL.refer方法会生成一个Invoker对象。REF_PROTOCOLProtocol接口的一个自适应代理类。

根据urls.get(0)来判断,REF_PROTOCOL对象的值为RegistryProtocol,当然因为Protocol的实现类有Wrapper类,RegistryProtocol会被Wrapper类包裹一层,这个Wrapper类为ProtocolFilterWrapperProtocolListenerWrapper

ProtocolListenerWrapper类作用为,当在dubbo获取到Invoker之后,我们可以设置一些回调,通过DubboSPI获取InvokerListener实例,可以对Invoker对象做一些处理工作。

Dubbo源码|二十一、Dubbo服务引入——创建代理对象

ProtocolFilterWrapper类主要作用为,通过Dubbo SPI获取Filter的所有实现类,并将其串联起来,最终返回的是一个FilterNode

Dubbo源码|二十一、Dubbo服务引入——创建代理对象

下面来看一下RegistryProtocolrefer方法。

Dubbo源码|二十一、Dubbo服务引入——创建代理对象

该方法处理逻辑如下:

  1. 根据url来获取注册中心。
  2. url中获取refer对应的值,这个值代表引用的服务。
  3. 根据服务参数中的分组信息,来判断使用哪一个Cluster
  4. 如果有多个分组,或者分组为*,则使用MergeableClusterInvoker
  5. 如果没有指定分组,则使用FailoverClusterInvoker
  6. 最后,调用doRefer方法创建Invoker

url中获取refer的值示例如下:

application=dubbo-demo-annotation-consumer&dubbo=2.0.2&init=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello,sayHelloAsync&pid=3023&register.ip=172.17.0.157&side=consumer&sticky=false&timestamp=1671457001297

doRefer

doRefer方法中,会通过Dubbo SPI获取RegistryProtocolListener的实现类,然后对实现类,进行循环调用onRefer方法,最终会返回Invoker对象。

这里也会处理一下服务的监听,这一块后面再进行介绍。

join

String cluster = registryURL.getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME);
invoker = Cluster.getCluster(cluster).join(new StaticDirectory(invokers));

通过Clusterjoin方法,来将多个invokers合并成一个invoker

Dubbo源码|二十一、Dubbo服务引入——创建代理对象

Cluster是一个接口,通过Dubbo SPI进行加载具体的实例,从代码中,我们可以看到Cluster的默认实现为failover。但是在registryURL获取cluster时,判断如果不存在的话,就是用zone-aware,所以这里获取到的是ZoneAwareCluster

当有多个invoker时,在调用的时候,会循环判断invoker是否可用,如果可用的话才会执行调用。

后记

本文介绍Dubbo服务引入部分的源码分析,创建代理对象的过程以及源码分析,下篇将介绍服务目录的监听配置。