Dubbo 源码分析 - Dubbo 远程服务暴露流程(一)

前言

前面用了 7 篇文章 循序渐进 讲解了 Dubbo SPI 的使用方法与应用,为今后分析 Dubbo 源码与执行流程 奠定了基础。接下来会通过 3-4 篇文章讲解 Dubbo 服务远程暴露流程

先来看下阅读本文的基础:

  • 对 Dubbo SPI 有一定的了解
  • 对 Dubbo 的使用有所了解

再看几个说明

  • 本文内容全部基于 Dubbo 2.7.x 的源码
  • 文章内容是通过 debug 的调试源码的方式提炼核心步骤, 直接定位到重点
  • 建议按照文章说明用 debug 跟踪下源码

正文

Dubbo 整个服务暴露流程很复杂,要经过很多类 和 方法,并且大部分方法还很长,我们肯定不能一行一行代码去剖析。
所以本文的目的是把整个流程中 最核心的步骤 单独拿出来,做一个简易的时序图, 因此分析的更加 粗略

1. 服务暴漏入口

Dubbo 远程服务暴露的 隐藏入口ServiceConfig#export()方法, 不管你是用 API 还是 Spring 的方式去启动服务。
如下为 整个方法的源码,我们上面有提到我们需要从冗长的方法中 提取 核心步骤,而我们下面的核心步骤就是 doExport()方法

public synchronized void export() {
        // 是否需要暴露
        if (!shouldExport()) {
            return;
        }

        if (bootstrap == null) {
            bootstrap = DubboBootstrap.getInstance();
            bootstrap.init();
        }

        checkAndUpdateSubConfigs();

        //init serviceMetadata
        serviceMetadata.setVersion(version);
        serviceMetadata.setGroup(group);
        serviceMetadata.setDefaultGroup(group);
        serviceMetadata.setServiceType(getInterfaceClass());
        serviceMetadata.setServiceInterfaceName(getInterface());
        serviceMetadata.setTarget(getRef());
		
		// 是否延迟暴露
        if (shouldDelay()) {
            DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
        } else {
            doExport();
        }

        exported();
}

再次强调: 很明显上面有很长一段代码, 但我们关注的重点就只有 doExport方法, 其他的暂时不用管, 后面的文章会补充.

2. 核心流程

运行 Dubbo 官方 demo(或者源码中的测试用例等等),目的是将服务注册到 zookeeper 上(你也可以用其他注册中心),然后通过 debug 模式运行代码,初始断点就打在 ServiceConfig#export()方法上,然后一步一步跟下去,你就能梳理出下面的时序图(至少可以跟踪完图中ServiceConfig的方法)

在这里插入图片描述

3. 源码分析

上面的时序图中涉及到 4 个类,我们一个一个来看。

3.1 ServiceConfig

通过 debug 从初始断点ServiceConfig#export()一步一步往下跟踪,前 5 步都是肉眼可见的,具体代码就不贴了, 但是这里需要讲一下,为什么第 5 步调用了 PROTOCOL.export()方法就突然跳到 RegisterProtocol#export()方法。

来看一下 PROTOCOL的相关定义:

# 去除了一些修饰符
Protocol PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

而 Protocol 是一个扩展类,这个前面的文章中详细举例说明过。

@SPI("dubbo")
public interface Protocol {

    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
}

综上所得,第 5 步用到了 Dubbo SPI 的自适应扩展机制。

根据我们之前讲的可以得知:在调用 export()方法时,会动态生成一个Protocol$Adaptive, 然后根据传入的参数(要么是URL,要么是URL的包装类),取出对应的 key,比如 key 对应的值为 dubbo,那么获得扩展类就是 DubboProtocol,如果值是 register,那么获得的自适应扩展类就是 RegisterProtocol

那么我们来看下传入的参数是什么:

Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);

通过打断点,我们可以看出,当执行到上面那一行代码是,我们传入的参数如下图所示:
在这里插入图片描述
wrapperInvoker 里面包含了 invoker 对象,而 invoker 对象又包含了 url 对象,我们从 url 里面可以取出 protocol 的值为 register,因此我们最终获得的是RegisterProtocol,所以我们就可以接着把断点打到 RegisterProtocol#export()方法上。

当然,实际的过程更复杂,上面的Protocol接口还有对应的 Wrapper 包装类,这又涉及到 Dubbo SPI 的知识点,所以当调用 PROTOCOL#export()时,会产生如下的调用顺序:

  1. Protocol$Adaptive#export()
  2. ProtocolFilterWrapper#export()
  3. ProtocolListenerWrapper#export()
  4. RegistryProtocol#export()

这些之前关于 Dubbo SPI 的文章是有说明过的,这里再次提一下。

3.2 RegisterProtocol

紧接着上一步,我们来到了 RegisterProtocol#export()方法,该方法很长,我们直接找到下面一行代码:

		//export invoker
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);

该方法的具体代码如下:

	private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
        String key = getCacheKey(originInvoker);

        return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> {
            Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
			
			// 重点看这里 protocol.export(invokerDelegate)
            return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);
        });
    }

我们从上面提炼出核心步骤protocol.export(invokerDelegate), 从 3.1 小结可知,这里又会出现一条如下的调用链:

  1. Protocol$Adaptive
  2. ProtocolFilterWrapper
  3. ProtocolListenerWrapper
  4. DubboProtocol
3.3 DubboProtocol

到了这里,远程服务暴露流程先告一段落, openServer()会去开启一个 NettyServer(这里默认通信框架是 Netty),去建立连接,接收消息。 这些内容后面的文章会详细讲解。

总结

本文讲解了远程服务暴露的大致的流程, 希望达成的目的如下:

  1. 了解整个大的流程框架会经过哪些核心环节,
  2. 解决整个流程执行过程的疑惑(或者说如何打断点),

比如上面提到的为什么会从 ServiceConfig跳到 RegisterProtocol#export方法, 归根到底还是基于 Dubbo SPI 机制, 同时也证明了 Dubbo SPI 是研究 Dubbo 原理的基石。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值