7、dubbo源码分析 之 服务本地暴露

在上一篇文章我们分析了一下 dubbo 在服务暴露发生了哪些事,今天我们就来分析一下整个服务暴露中的本地暴露。(PS:其实我感觉本地暴露蛮鸡肋的)。本地暴露需要服务提供方与服务消费方在同一个 JVM。下面我们来写一个本地暴露使用的例子:

  1. DemoService.java
public interface DemoService {

    String sayHello(String name);

}
  1. DemoServiceImpl.java
public class DemoServiceImpl implements DemoService {

    public String sayHello(String name) {
        return "Hello " + name + ", response form provider: " + RpcContext.getContext().getLocalAddress();
    }

}
  1. application.xml -- Spring配置文件
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="demo-provider"/>

<!-- 和本地bean一样实现服务 -->
<bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />

<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" registry="N/A" scope="local"/>

<dubbo:reference id="demoServiceDubbo" interface="com.alibaba.dubbo.demo.DemoService"  injvm="true"/>
  1. Provider.java -- 调用本地暴露的服务
public class Provider {

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

        DemoService demoServiceDubbo = context.getBean("demoServiceDubbo", DemoService.class);
        String returnMessage = demoServiceDubbo.sayHello("carl");
        System.out.println(returnMessage);
    }

}

使用context.getBean("demoServiceDubbo", DemoService.class)这种方式来获取Bean还不如使用context.getBean("demoService", DemoService.class)来获取真正对象。前一种方式获取到是 dubbo 返回的代理类,其中可以获取到 dubbo 的InvokerListenerFilter这两个扩展点。可能这是与整个服务保持统一性吧。(大家如果有不同的观点欢迎留言)。下面我们就从源码的角度来分析一下 dubbo 的本地暴露吧。

如果大家看过dubbo官网的API配置(建议大家分析码源的时候都使用API的形式调用,尽量少的引入第三方Jar包比如xml配置dubbo),我们就可以知道。dubbo服务的暴露的起点是ServiceConfig#export。下面我们就以这个方法以起点来分析它:

这里写图片描述

export这个方法就是dubbo服务暴露的入口,主要就是判断这个服务是否暴露以及通过ScheduledThreadPoolExecutor这个线程池类支持延迟暴露。

这里写图片描述

接下来就是doExport方法,在这个方法的前面就是做一些 check 操作,不是重点,就不一一分析了。我们主要看一下它的appendProperties方法以及doExportUrls这两个方法。appendProperties()方法主要是为当前对象通过setter 方法来添加属性,它主要是通过以下方式来添加属性:

  • 从 System 中获取属性key值的优先通讯是: dubbo.provider. + 当前类 Id + 当前属性名称 > dubbo.provider. + 当前属性名称 为 key 获取值.
  • 首先从特定properties文件加载属性:首先 System.getProperty("dubbo.properties.file")获取到文件路径,如果获取不到就会试图加载 dubbo 的默认的路径 dubbo.properties加载。获取属性的 key 和上面从 System 里面获取的规则一样。

然后我们就来分析一下doExportUrl这个方法,因为 Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。所以这里需要循环各个协议进行多协议暴露服务。

private void doExportUrls() {
    List<URL> registryURLs = loadRegistries(true);
    for (ProtocolConfig protocolConfig : protocols) {
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}

然后我们来分析一下ServiceConfig#doExportUrlsFor1Protocol,首先我们来看一下appendParameters(Map, Object)这个方法,这个方法的作用就是通过调用当前对象的getter方法获取到传入对象的值然后塞到 map 当中去。用于后面的构造URL这个对象。

public final class URL implements Serializable {

    private static final long serialVersionUID = -1985165475234910535L;
    // 协议
    private final String protocol;
    // 用户名
    private final String username;
    // 密码
    private final String password;
    // 主机
    private final String host;
    // 端口
    private final int port;
    // path
    private final String path;
    // 其它参数
    private final Map<String, String> parameters;
}

注:URL,配置信息的统一格式,所有扩展点都通过传递 URL 携带配置信息)

这里写图片描述

如果大家没有看过我6、dubbo源码分析 之 服务暴露概述在这点我再向大家提醒一下,dubbo的对象扭转过程是:

服务配置类 --> Invoker --> Exporter

首先通过 ref (服务实现类)、服务接口类以及 URL 默认通过 javassist,也就是 JavassistProxyFactory类获取到代理对象。

这里写图片描述

然后再把 Invoker 对象转化成Exporter对象。还记得之前的5.dubbo源码分析 之 SPI分析之前是分析的远程暴露中的获取Protocol 实例。只是这里的 protocol实例是 本地方法暴露获取的实例。它也是 dubbo 自定义的 SPI 生成的 Protocol$Adaptive通过它的getExtension(name)方法创建 Protocol实例,然后通过 Protocol#export 方法获取Exporter

这里写图片描述

我们可以看到Protocol$Adaptive这个类生成的 Protocol对象的结构是:

  • ProtocolListenerWrapper
    • ProtocolFilterWrapper
      • InjvmProtocol

dubbo 的定义 SPI 里面包括 AOP,其实就是获取到所有的 SPI 接口的实例对象。然后在调用 getExtension(name)方法返回指定名字的扩展的时候会判断哪些实现类的构造器只包含 SPI 接口就会进行代理。这里的name是从 URL 中获取协议。在调用ServiceConfig#loadRegistries方法的里面返回的 URL 格式为registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?xxx=xxx然后再调用ServiceConfig#exportLocal(URL)方法的时候里面把协议(protocol)设置成injvm, 然后 在 Protocol$Adaptive 进行服务暴露的时候:

这里写图片描述

因为 duubo 默认在dubbo-rpc-injvm的自定义Protocol配置文件(${dubbo-rpc-injvm}/src/main/resources/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol)配置的是injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol所以得到的对象是InjvmProtocol。因为ProtocolListenerWrapperProtocolFilterWrapper 其实都包括 SPI 接口 Protocol的构造器。所以创建出来的对象如上所以。关于 dubbo 的SPI机制可以参看 -- 2.dubbo源码分析 之 内核SPI实现.

  • ProtocolListenerWrapper : 通过 SPI 机制获取到 dubbo 的自定义扩展 InvokerListener
  • ProtocolFilterWrapper : 通过 SPI 机制获取到 dubbo 的自定义扩展 Filter(常用)。

其实关于 dubbo 通过 SPI 机制获取机制获取到 dubbo 的自定义扩展 Filter,还蛮复杂与重要的。在这里就不多说了,感兴趣的朋友可以下去参看源码。

最终就到了InjvmProtocol暴露服务,其实它就是创建一个 InjvmExporter 对象返回。里面包括 4 个属性:

  • invoker:Invoker 对象实例
  • key:服务 key 值,在进行服务调用的时候会根据这个 key 值。获取到当前服务暴露生成的 Exporter 对象。
  • exporterMap:服务 key 值与当前 Exporter 的映射

最后这个生成的 Exporter 最终会返回添加到 ServiceConfigexporters 属性当中去。这样就完成了 dubbo 服务暴露的本地暴露的过程。

这里写图片描述

其实整个 dubbo 的本地暴露逻辑还是蛮简单的,把它分开来主要还是整个服务暴露过程比较复杂。先给大家讲解一下本地暴露。如果大家清楚了本地暴露,然后再理解远程暴露就会更加容易。

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

推荐阅读更多精彩内容