8、dubbo源码分析 之 服务远程暴露(上)

在上一篇文章我们讲解了一下 dubbo 服务暴露过程中的本地暴露。它只是一个开胃小菜,主要是为我们后面讲解远程暴露开个头。下面就来分析一下 dubbo 在远程暴露里面发生了哪些事。因为 dubbo 远程暴露里面的过程还是比较复杂的,所以我就分为三个文章来讲解 dubbo 的远程暴露:

  1. dubbo 远程暴露 -- Netty 暴露服务
  2. dubbo 远程暴露 -- Zookeeper 连接
  3. dubbo 远程暴露 -- Zookeeper 注册 & 订阅

这就篇就是分析 dubbo 服务暴露中通过 Netty 来暴露服务(当然 dubbo 还可以通过 Mina、Grizzly 来暴露服务,默认使用 Netty)。

1、ServiceConfig#doExportUrls

首先通过方法loadRegistries(true)来加载注册中心。在方法checkRegistry()方法中判断如果 xml 里面没有配置注解中心,从 dubbo 的 properties 文件中获取(默认是dubbo.properties)。然后会返回List<URL> 作为配置信息的统一格式,所有扩展点都通过传递 URL 携带配置信息。URL的格式如下:

registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0 ...

因为 dubbo 支持多种协议,遍历所有协议分别根据不同的协议把服务export到不同的注册中心上去。

  1. 把配置的信息通过appendParameters提取到 map 中
  2. 判断是否支持泛化调用
  3. 通过协议名称、host、port、contextPath 和第一步提取出来的 map 构造协议的统一数据模型 URL (如:dubbo://169.254.69.197:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider ...)
  4. 循环遍注册中心,把服务暴露在不同的注册中心当中
    a) 如果配置了 monitor,就返回监控统一模型数据 URL,并给以 monitor为 key 添加到生成的 URL中,URL格式如下:
    registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?export=dubbo%3A%2F%2F169.254.69.197%3A20880%2Fcom.alibaba.dubbo.demo.DemoService& ...
    b) 把协议统一模型 URL 以export为 key,添加到注册中心的统一模型 URL中
    c) 根据服务的具体实现、实现的接口以及注册中心统一模型 URL从代理工厂 ProxyFactory(SPI 默认获取到 JavassistProxyFactory)获取 Invoker对象。
    这里写图片描述

    d) 通过 Protocol#export(invoker) 暴露服务,因为注册的协议是 registry 所以生成的 Protocol 对象如下图所示。因为 ProtocolFilterWrapperProtocolFilterWrapper是过滤 registry协议的,所以最终通过 RegistryProtocol来处理暴露过程。
    这里写图片描述

2、RegistryProtocol#export

根据这个类名我们就可以推测出这个类具有的功能,具有 Registry(注册)与 Protocol (协议--服务暴露)在这个方法里面就包括上面提到的三个逻辑:

  • dubbo 远程暴露 -- Netty 暴露服务,通过配置的协议根据 SPI 获取到对应的 Protocol对象,这里是 DubboProtocol,对象。
  • dubbo 远程暴露 -- Zookeeper 连接 服务注册,通过RegistryFactory根据 SPI 获取对应的 Registry 对象(ZookeeperRegistry),然后注册到注册中心上面去,供 consumer调用
  • dubbo 远程暴露 -- Zookeeper 注册 & 订阅,它会把创建2个节点:一个是/dubbo/服务全类名/provider/...节点提供给服务消费方查看节点信息;二是/dubbo/服务全类名/configurators/...节点提供给服务方 watch(监控) dubbo-admin 对于服务的修改。比如:服务权重。

上面粗略的讲了一下服务远程暴露主要干了哪些事,主要是想让大家有一个全局的意识。下面我们就来讲一下 dubbo 服务是如何通过 Netty 来暴露服务。

  1. getCacheKey(originInvoker),通过 Invoker 对象获取到缓存 key,还记得我们在ServiceConfig#doExportUrls的 4-b 步骤里面吗?它就是把保存在 注册统一模型里面的 export key 获取到协议的统一模型dubbo://169.254.69.197:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider ...,然后再删除 dynamicenabled 参数
  2. Map<String, ExporterChangeableWrapper<?>> bounds缓存中根据上面获取的 key 获取 Exporter 对象,如果获取到直接返回;否则进行服务暴露
  3. 通过 originInvoker获取里面的 URL 获取到协议的统一模型以及originInvoker本身创建 InvokerDelegete
  4. 根据InvokerDelegete暴露服务,因为 URL 协议是 dubbo,所以获取到的实例是 DubboProtocol,而这个对象因为协议不是 registry,所以生成ProtocolListenerWrapper会根据 SPI 机制检测 dubbo 里面配置的 InvokerListener 扩展;而 ProtocolFilterWrapper 会根据 SPI机制检测 dubbo里面配置的 Filter 扩展。所以最终通过 DubboProtocol来处理暴露过程。
    这里写图片描述
  5. 暴露生成的 Exporter 和 传入的 originInvoker 会创建 ExporterChangeableWrapper对象会以步骤 1 生成的 key 缓存在 Map<String, ExporterChangeableWrapper<?>> bounds 当中,并返回结果。

3、DubboProtocol#export

整个DubboProtocol#export的代码如下:

    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        URL url = invoker.getUrl();

        // export service.
        String key = serviceKey(url);
        DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
        exporterMap.put(key, exporter);

        //export an stub service for dispaching event
        Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
        Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
        if (isStubSupportEvent && !isCallbackservice) {
            String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
            if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
                if (logger.isWarnEnabled()) {
                    logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) +
                            "], has set stubproxy support event ,but no stub methods founded."));
                }
            } else {
                stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
            }
        }

        openServer(url);

        return exporter;
    }

这断代码主要的操作是:

  1. 根据传入的Invoker中的 URL 通过serviceKey(url)获取到 serviceKey,它的格式为:com.alibaba.dubbo.demo.DemoService:20880.
  2. 以传的Invoker、第 1 步生成的 key 和 Map<String, Exporter<?>> exporterMap 生成 DubboExporter,并以第 1 步生成的 key 为索引,把生成的 DubboExporter添加到Map<String, Exporter<?>> exporterMap
  3. 根据 URL 判断是不是服务端,如果是服务端并且从Map<String, ExchangeServer> serverMap获取到的 ExchangeServer 为空,就通过DubboProtocol#createServer 创建服务,达到服务暴露的目的。返回DubboExporter对象

4、DubboProtocol#createServer

dubbo 远程服务(Provider)暴露最终其实就是创建一个 Netty Serve 服务,然后在 dubbo 在服务引用的时候创建一个 Netty Client 服务。其实 dubbo 远程通信的原理其实就是基于 Socket 的远程通信。下面我们来看一下 dubbo 是如何创建一个 Netty 服务的,下面就是它创建的序列图:

这里写图片描述

它通过传入 URL 与 requestHandler来创建一个 ExchangeServer,通过Netty 基于 NIO的形式通过自定义Channel来接收服务引用方传递过来的信息,以及发送调用远程服务的本地方法后的数据给服务调用者。URL 里面主要包含 IP 地址 与 端口信息用于创建 Socket 连接,而 requestHandler是一个 ExchangeHandler 通过自定义协议来处理 dubbo 的远程通信。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容