Dubbo服务消费源码分析

总结:
(1)Dubbo服务消费通过持有远程服务实例生成Invoker,这个Invoker在客户端是核心的远程代理对象。把Invoker通过动态代理转成实现用户接口的动态代理引用。
(2)服务引用的入口在ReferenceBean#getObject,不管是XML还是注解,都会转换成ReferenceBean。

引入一个Dubbo服务,可以使用@Reference注解或者在xml配置dubbo:reference标签。

ReferenceBean是FactoryBean的子类。实例化ReferenceBean会调用getObject方法生成对象。ReferenceBean#getObject调用父类ReferenceConfig#get获取一个对象。

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

ReferenceConfig#get:检查更新参数配置,调用init方法创建一个接口代理,并返回。

public synchronized T get() {
    checkAndUpdateSubConfigs();

    if (destroyed) {
        throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
    }
    if (ref == null) {
        init();
    }
    return ref;
}

ReferenceConfig#init 创建接口代理。

private void init() {
    if (initialized) {
        return;
    }
    //省略:将@Reference或者properties文件配置的参数放入map。
    //创建代理
    ref = createProxy(map);
    initialized = true;
}

ReferenceConfig#createProxy
REF_PROTOCOL、CLUSTER和PROXY_FACTORY都是Adaptive代理类。

ReferenceConfig#createProxy
(1)shouldJvmRefer:检查是否是同一个JVM的调用。如果是,直接使用injvm协议,从内存中获取实例。
(2)loadRegistries:加载Registry类型的URL。
a,如果注册url只有一个,直接调用REF_PROTOCOL#refer创建一个invoker;Cluster包装顺序是:MockClusterWrapper->FailoverCluster(默认)。
b.如果注册url有多个,创建一个Invoker集合,最后一个注册URL添加参数cluster=registryaware。调用Cluster#join将多个Invoker合并成一个Invoker。Cluster包装顺序:MockClusterWrapper->RegistryAwareCluster。
最后创建接口代理。

Protocol REF_PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
private static final Cluster CLUSTER = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension();
private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

private T createProxy(Map<String, String> map) {
	if (shouldJvmRefer(map)) {
    } else {
		//省略代码。。。。
		List<URL> us = loadRegistries(false);
	    if (CollectionUtils.isNotEmpty(us)) {
	        for (URL u : us) {
	            URL monitorUrl = loadMonitor(u);
	            if (monitorUrl != null) {
	                map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
	            }
	            urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
	        }
	    }
	}
	
	//省略
	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 (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                registryURL = url; //使用最后一个注册URL
            }
        }
        if (registryURL != null) { //注册URL是可用的
            //添加参数cluster=registryaware
            URL u = registryURL.addParameter(CLUSTER_KEY, RegistryAwareCluster.NAME);
            invoker = CLUSTER.join(new StaticDirectory(u, invokers));
        } else { //不是注册URL,直接调用。
            invoker = CLUSTER.join(new StaticDirectory(invokers));
        }
    }

    //省略

    return (T) PROXY_FACTORY.getProxy(invoker);

}

REF_PROTOCOL#refer调用顺序:
Protocol$Adaptive#refer
–>ProtocolFilterWrapper#refer
–>QosProtocolWrapper#refer
–>ProtocolListenerWrapper#refer
–>RegistryProtocol#refer
–>RegistryProtocol#doRefer

RegistryProtocol#refer
创建具体注册中心实例(如ZookeeperRegistry),调用doRefer方法创建Invoker。

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(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);
}

RegistryProtocol#doRefer:封装一个RegistryDirectory实例,RegistryDirectory是NotifyListener的子类,也是一个通知器。将消费url注册到注册中心。构造路由链,订阅providers(服务提供者)、configurators(动态配置)和routers(路由)目录的变化,调用Cluster#join合并Invokers。

subscribeUrl:
consumer://192.168.1.107/gdut.DemoService?application=dubbbo-consumer-demo
&dubbo=2.0.2&interface=gdut.DemoService&lazy=false&methods=sayHello,sayHelloAsync&pid=2912&qos.enable=false&release=2.7.3&revision=default&side=consumer&sticky=false&timestamp=1636885284173&version=default

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;
}

RegistryProtocol#refer
–>RegistryProtocol#doRefer
–>RegistryDirectory#subscribe
–>FailbackRegistry#subscribe
–>ZookeeperRegistry#doSubscribe
–>FailbackRegistry#notify
–>FailbackRegistry#doNotify
–>AbstractRegistry#notify
–>RegistryDirectory#notify
–>RegistryDirectory#refreshOverrideAndInvoker
–>RegistryDirectory#refreshInvoker
–>RegistryDirectory#toInvokers
–>QosProtocolWrapper#refer
–>ProtocolFilterWrapper#refer
–>ProtocolListenerWrapper#refer
–>AbstractProtocol#refer
–>DubboProtocol#protocolBindingRefer
–>DubboProtocol#getClients
–>DubboProtocol#getSharedClient
–>DubboProtocol#buildReferenceCountExchangeClientList
–>DubboProtocol#buildReferenceCountExchangeClient
–>DubboProtocol#initClient

RegistryDirectory#subscribe 将当前这个RegistryDirectory实例添加到监听器集合。
registry#subscribe最终会调用具体的registry实现类(如ZookeeperRegistry)的doSubscribe方法。

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

DubboProtocol#protocolBindingRefer 创建DubboInvoker。DubboInvoker是AbstractInvoker的子类。

 public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {
    optimizeSerialization(url);

    // create rpc invoker.
    DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
    invokers.add(invoker);

    return invoker;
}

DubboProtocol#initClient 建立客户端连接和初始化Handler。
判断是否lazy延迟连接,默认是false,如果是延迟连接,会在发生RPC调用时才创建客户端连接。如果不是延迟连接,会立即发起远程TCP连接。调用HeaderExchanger#connect构造HeaderExchangeClient。

private ExchangeClient initClient(URL url) {
        //省略代码
        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;
    }

HeaderExchanger#connect 创建Netty客户端

 public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
    return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);
}

构造路由链

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

获取到的extensionFactories一共有4种:MockRouterFactory(Mock路由),TagRouterFactory(标签路由),AppRouterFactory(应用条件路由),ServiceRouterFactory(服务条件路由)

获取到的routers:MockInvokersSelector,TagRouter,AppRouter,ServiceRouter

RouterChain#initWithRouters 将上面获取的路由链赋值给RouterChain的变量并排序。

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);
}

public void initWithRouters(List<Router> builtinRouters) {
    this.builtinRouters = builtinRouters;
    this.routers = new ArrayList<>(builtinRouters);
    this.sort();
}

cluster.join(directory)获得的是一个MockClusterInvoker。
MockClusterWrapper#join会将自己包装的cluster得到的Invoker包装成一个MockClusterInvoker。

public class MockClusterWrapper implements Cluster {

    private Cluster cluster;

    public MockClusterWrapper(Cluster cluster) {
        this.cluster = cluster;
    }

    @Override
    public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
        return new MockClusterInvoker<T>(directory,
                this.cluster.join(directory));
    }

}

RegistryAwareCluster #join利用传入的目录资源构造一个RegistryAwareClusterInvoker对象。

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);
    }
}

FailoverCluster#join利用传入的目录资源构造一个FailoverClusterInvoker对象。

public class FailoverCluster implements Cluster {

    public final static String NAME = "failover";

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

}

MockClusterInvoker: 完成Mock功能,由MockClusterWrapper⽣成。
FailoverClusterInvoker:完成集群容错功能。默认。
RegistryAwareClusterInvoker:如果指定了多个注册中心,RegistryAwareClusterInvoker会选择默认的注册中心(设置registry.default=true)进行调用,如果没有指定默认的,则会遍历注册中心进行调用,如果该注册中心没有对应的服务则跳过。

PROXY_FACTORY.getProxy
把Invoker转成接口代理有两种实现,最终都会创建InvokerInvocationHandler。InvokerInvocationHandler是JDK的InvocationHandler的子类,最终接口都是交给代理去发起远程调用。

(1)JavassistProxyFactory#getProxy

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

(2)JdkProxyFactory#getProxy

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

Dubbo也允许直连服务发起RPC调用,不经过注册中心。

ReferenceConfig#createProxy的一个分支判断。
直连地址url用于点对点的调用,可以用分号指定多个直连机器地址,多个直连机器调用会使用负载均衡。直连地址也可以配置成注册中心地址,允许发现服务,如果不是注册中心地址,需要指定服务调用协议,IP,端口,触发对应的Protocol(如DubboProtocol)进行远程调用,不经过RegistryProtocol做服务发现。

/**
 * The url for peer-to-peer invocation
 */
private String url;

Pattern SEMICOLON_SPLIT_PATTERN = Pattern.compile("\\s*[;]+\\s*");

 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 (REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
            } else {
                urls.add(ClusterUtils.mergeUrl(url, map));
            }
        }
    }
}    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值