关于dubbo:dubbo-client引用远程服务逻辑探究

3次阅读

共计 6182 个字符,预计需要花费 16 分钟才能阅读完成。

本文次要记录下本人浏览源码时的一些了解,本文次要聊下 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 进行实现类适配,由 SPI 内容
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 优良的抽象化,模块化,层次化设计,代码的复用性很高,直连的实现逻辑也很简略

正文完
 0