dubbo client引用远程服务逻辑探究

本文主要记录下自己阅读源码时的一些理解,本文主要聊下dubbo client是如何引用远程服务的,以使用zookeeper作为注册中心为例。

接口声明及客户端调用方式如下:

public interface DemoService {
    String sayHello(String name);
}

public class Consumer2 {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"});
        context.start();
        DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy
        String hello = demoService.sayHello("world"); // call remote method
        System.out.println(hello); // get result
    }
}

由于 dubbo 最近在做比较大的版本变迁,但是其核心接口并没变,所以这里以 2.6.x的版本为例讲解,由于我们选用的 server 实现是netty4,所以我们在 netty 的 NettyClient.doConnect 方法加入一个断点,得到的调用栈如下:
以dubbo官方demo为例的客户端调用栈:

34. doConnect:116, NettyClient (com.alibaba.dubbo.remoting.transport.netty4)
33. connect:353, AbstractClient (com.alibaba.dubbo.remoting.transport)
32. <init>:130, AbstractClient (com.alibaba.dubbo.remoting.transport)
31. <init>:64, NettyClient (com.alibaba.dubbo.remoting.transport.netty4)
30. connect:39, NettyTransporter (com.alibaba.dubbo.remoting.transport.netty4)
29. connect:-1, Transporter$Adaptive (com.alibaba.dubbo.remoting)
28. connect:81, Transporters (com.alibaba.dubbo.remoting)
27. connect:40, HeaderExchanger (com.alibaba.dubbo.remoting.exchange.support.header)
26. connect:111, Exchangers (com.alibaba.dubbo.remoting.exchange)
25. initClient:612, DubboProtocol (com.alibaba.dubbo.rpc.protocol.dubbo)
24. getSharedClient:569, DubboProtocol (com.alibaba.dubbo.rpc.protocol.dubbo)
23. getClients:533, DubboProtocol (com.alibaba.dubbo.rpc.protocol.dubbo)
22. refer:504, DubboProtocol (com.alibaba.dubbo.rpc.protocol.dubbo)
21. refer:71, ProtocolListenerWrapper (com.alibaba.dubbo.rpc.protocol)
20. refer:133, ProtocolFilterWrapper (com.alibaba.dubbo.rpc.protocol)
19. refer:-1, Protocol$Adaptive (com.alibaba.dubbo.rpc)
18. toInvokers:530, RegistryDirectory (com.alibaba.dubbo.registry.integration)
17. refreshInvoker:349, RegistryDirectory (com.alibaba.dubbo.registry.integration)
16. notify:305, RegistryDirectory (com.alibaba.dubbo.registry.integration)
15. notify:490, AbstractRegistry (com.alibaba.dubbo.registry.support)
14. doNotify:305, FailbackRegistry (com.alibaba.dubbo.registry.support)
13. notify:290, FailbackRegistry (com.alibaba.dubbo.registry.support)
12. doSubscribe:241, ZookeeperRegistry (com.alibaba.dubbo.registry.zookeeper)
11. subscribe:216, FailbackRegistry (com.alibaba.dubbo.registry.support)
10. subscribe:219, RegistryDirectory (com.alibaba.dubbo.registry.integration)
9. doRefer:309, RegistryProtocol (com.alibaba.dubbo.registry.integration)
8. refer:290, RegistryProtocol (com.alibaba.dubbo.registry.integration)
7. refer:68, ProtocolListenerWrapper (com.alibaba.dubbo.rpc.protocol)
6. refer:130, ProtocolFilterWrapper (com.alibaba.dubbo.rpc.protocol)
5. refer:-1, Protocol$Adaptive (com.alibaba.dubbo.rpc)
4. createProxy:402, ReferenceConfig (com.alibaba.dubbo.config)
3. init:334, ReferenceConfig (com.alibaba.dubbo.config)
2. get:163, ReferenceConfig (com.alibaba.dubbo.config)
1. main:35, Consumer2 (com.alibaba.dubbo.demo.consumer)

下面进行逐步拆解:
1、 main方法,入口
2、 ReferenceConfig.get 简单判断当前引用是否销毁,是否初始化过,否则进入初始化逻辑
3、 ReferenceConfig.init 初始化逻辑,参数校验、初始化,检查是否是泛化调用,组装URL
4、 ReferenceConfig.createProxy 检查是否是 injvm(即本地调用) 调用,处理直连url调用,否则从注册中心获取引用,包括多注册中心
5、 Protocol$Adaptive 调用Protocol的自适应实现类进行 refer,根据 url 参数中的 protocol 进行实现类适配
6-7、 ProtocolFilterWrapper、ProtocolListenerWrapper都是 protocol 的 Wrapper 类,会自动包装在 protocol 的实现类上,由 SPI 机制实现自动注入
8、 由于目前的url中的 protocol 为 registry,所以实现类为 RegistryProtocol,该方法中将 url 的protocol 改为 zookeeper,由 SPI 获取注册中心的实现类 ZookeeperRegistry,判断有无group设置,有则使用 mergeable cluster 进行合并,没有 group 则使用 SPI 指定的 cluster 进行集群容错
9、 RegistryProtocol.doRefer 将zookeeper 目录转换为一个动态 Directory ,将客户端作为 consumer 写入到注册中心,同时订阅providers、configurators、routers,启动集群容错策略,默认是 FailoverClusterInvoker,同时根据 SPI 包装一个 MockClusterInvoker 进行本地存根、服务降级增强
10、下面开始拉取注册中心内容
11、 FailbackRegistry 是一个注册中心实现的父类,实现了注册中心容错逻辑,主要功能是如果请求注册中心失败了会自动进行重试,默认重试周期5s
12、ZookeeperRegistry.doSubscribe 进行 zookeeper 订阅请求并获得一个初始值进行 notify 回调
13、FailbackRegistry.notify 进行简单的参数校验和容错,调用 FailbackRegistry.doNotify
14、FailbackRegistry.doNotify 直接调用父类实现
15、AbstractRegistry.notify 将回调进行分类,并调用对应的回调函数
16、由于这个订阅最初是RegistryDirectory发起订阅的,回调最终执行到 RegistryDirectory.notify,这里对回调进行处理,这里处理了 configurators、routers 两种监听的回调
17、 RegistryDirectory.refreshInvoker 处理providers数据回调,刷新invoker 列表,如果没有匹配的providers则设置禁用,对所有请求返回错误,否则将providers转换为invoker,刷新本地invoker列表,这个列表里的invoker即是具体一个ip:port的网络调用了,当然这些invoker也进行了过滤器等增强
18、RegistryDirectory.toInvokers 即是将多个 providers 的注册内容即url进行转换为具体的invoker逻辑,这里因为使用dubbo协议就是 DubboInvoker
19、初始化 invoker 逻辑,根据 SPI 协议自适应调用对应的 Protocol 实现类
20-21、 ProtocolFilterWrapper、ProtocolListenerWrapper就不多说了,协议增强类,会被 SPI 自动包装到具体的实现类上
22、因为用dubbo 这里的协议实现类是 DubboProtocol
23、getClients获取对应链接,根据配置决定是共享 client 还是独享 client
24、getSharedClient 默认是共享链接
25、initClient 因为无连接可用,这里创建一个新的链接
26-27、Exchangers 工厂类,使用 SPI获取具体实现类 HeaderExchanger
28-30、Transporters 工厂类,根据SPI获取自适应Transporter,由于我配置了client=netty4所以这里是netty4.NettyTransporter
31-34、委托到netty4的 bootstrap.connect 具体进行链接创建

整体逻辑还是比较简单的,即从注册中心订阅到providers的url列表,转换为本地Invoker列表,并添加集群容错、过滤器等逻辑,如果用url直连的方式这个调用栈会简化很多,如下示例:

doConnect:116, NettyClient (com.alibaba.dubbo.remoting.transport.netty4)
connect:353, AbstractClient (com.alibaba.dubbo.remoting.transport)
<init>:130, AbstractClient (com.alibaba.dubbo.remoting.transport)
<init>:64, NettyClient (com.alibaba.dubbo.remoting.transport.netty4)
connect:39, NettyTransporter (com.alibaba.dubbo.remoting.transport.netty4)
connect:-1, Transporter$Adaptive (com.alibaba.dubbo.remoting)
connect:81, Transporters (com.alibaba.dubbo.remoting)
connect:40, HeaderExchanger (com.alibaba.dubbo.remoting.exchange.support.header)
connect:111, Exchangers (com.alibaba.dubbo.remoting.exchange)
initClient:612, DubboProtocol (com.alibaba.dubbo.rpc.protocol.dubbo)
getSharedClient:569, DubboProtocol (com.alibaba.dubbo.rpc.protocol.dubbo)
getClients:533, DubboProtocol (com.alibaba.dubbo.rpc.protocol.dubbo)
refer:504, DubboProtocol (com.alibaba.dubbo.rpc.protocol.dubbo)
refer:73, ProtocolListenerWrapper (com.alibaba.dubbo.rpc.protocol)
refer:133, ProtocolFilterWrapper (com.alibaba.dubbo.rpc.protocol)
refer:-1, Protocol$Adaptive (com.alibaba.dubbo.rpc)
createProxy:402, ReferenceConfig (com.alibaba.dubbo.config)
init:334, ReferenceConfig (com.alibaba.dubbo.config)
get:163, ReferenceConfig (com.alibaba.dubbo.config)
main:35, Consumer2 (com.alibaba.dubbo.demo.consumer)

直连逻辑跳过了注册中心,实现上更直接,得益于 dubbo 优秀的抽象化,模块化,层次化设计,代码的复用性很高,直连的实现逻辑也很简单

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

推荐阅读更多精彩内容