最近在阅读dubbo的源码,记录下阅读的一些关键点,本文主要探究dubbo客户端请求发送逻辑;
接口声明及客户端调用方式如下:
public interface DemoService {
String sayHello(String name);
}
public class Consumer {
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官方demo为例的客户端调用栈:
22. writeAndFlush:244, AbstractChannel (io.netty.channel)
21. send:116, NettyChannel (com.alibaba.dubbo.remoting.transport.netty4)
20. send:336, AbstractClient (com.alibaba.dubbo.remoting.transport)
19. send:58, AbstractPeer (com.alibaba.dubbo.remoting.transport)
18. request:146, HeaderExchangeChannel (com.alibaba.dubbo.remoting.exchange.support.header)
17. request:115, HeaderExchangeClient (com.alibaba.dubbo.remoting.exchange.support.header)
16. request:95, ReferenceCountExchangeClient (com.alibaba.dubbo.rpc.protocol.dubbo)
15. doInvoke:126, DubboInvoker (com.alibaba.dubbo.rpc.protocol.dubbo)
14. invoke:185, AbstractInvoker (com.alibaba.dubbo.rpc.protocol)
13. invoke:86, ListenerInvokerWrapper (com.alibaba.dubbo.rpc.listener)
12. invoke:75, MonitorFilter (com.alibaba.dubbo.monitor.support)
11. invoke:93, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
10. invoke:55, FutureFilter (com.alibaba.dubbo.rpc.protocol.dubbo.filter)
9. invoke:93, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
8. invoke:53, ConsumerContextFilter (com.alibaba.dubbo.rpc.filter)
7. invoke:93, ProtocolFilterWrapper$1 (com.alibaba.dubbo.rpc.protocol)
6. invoke:59, InvokerWrapper (com.alibaba.dubbo.rpc.protocol)
5. doInvoke:90, FailoverClusterInvoker (com.alibaba.dubbo.rpc.cluster.support)
4. invoke:294, AbstractClusterInvoker (com.alibaba.dubbo.rpc.cluster.support)
3. invoke:84, MockClusterInvoker (com.alibaba.dubbo.rpc.cluster.support.wrapper)
2. invoke:57, InvokerInvocationHandler (com.alibaba.dubbo.rpc.proxy)
1. sayHello:-1, proxy0 (com.alibaba.dubbo.common.bytecode)
main:38, Consumer2 (com.alibaba.dubbo.demo.consumer)
dubbo 虽然现在在经历比较大的版本变迁,但是其核心调用逻辑并未改变,我们在传输层组件netty的writeAndFlush方法加入一个断点得到如上的调用栈
下面进行逐步拆解:
1、 proxy0 是dubbo使用ProxyFactory生成的代理类,默认是 javassist 生成的字节码,具体生成代码逻辑在 com.alibaba.dubbo.common.bytecode.Proxy.getProxy(Class>...)
2、InvokerInvocationHandler 代理类的具体处理逻辑,经过代理可以拿到调用接口的方法签名Method及参数,可以参考jdk自带的动态代理来理解
3、MockClusterInvoker是 MockClusterWrapper 创建的 clusterInvoker,而 MockClusterWrapper 是 一个cluster的自动包装(Wrapper)类,dubbo的 spi扩展在初始化的时候会自动寻找 Wrapper 包装在扩展实现上,参考dubbo的 SPI 扩展, MockClusterInvoker 提供了 服务降级和本地伪装的能力, 结合 MockInvokersSelector 实现服务降级,结合 MockProtocol、MockInvoker 实现本地伪装
4-5、FailoverClusterInvoker 是默认的集群容错策略,即失败自动切换策略,值得一提的是 负载均衡器(LoadBalance)也是工作在这个组件下
6、InvokerWrapper 是 Invoker 的增强类,绑定了 URL 信息, 实现了 Node 接口,真实实现还是委托给内部的 Invoker 实例,从构造器上看它并不是一个 SPI Wrapper 类,它是被 RegistryDirectory 手动实例化的
7-12、 ProtocolFilterWrapper$1 是 过滤器(Filter) 链,ProtocolFilterWrapper 是对 Protocol的增强,加入了过滤器功能,他将 filter 数组与 Invoker实现组成一个过滤器链表;同样 ProtocolFilterWrapper 也是一个 Wrapper 包装类,通过 SPI 自动包装在默认的 Protocol 实现类 DubboProtocol 上,与 3 类似
13、ListenerInvokerWrapper 是对Invoker的一个装饰者模式增强,它实现了对invoker的refer及destroy的监听回调,但ListenerInvokerWrapper不是一个 SPI 包装类(Wrapper),因为它没有 Wrapper 类的标志性构造器
14-15、是 DubboInvoker(默认dubbo协议Invoker) 的调用(invoke)逻辑,该方法会调用 ExchangeClient 将请求发出到网络,ExchangeClient 中包括了编码器、序列化组件等初始化逻辑,最终将这些组件设置进netty的 channelhandler,在调用 netty channel的write 方法时会执行具体的编码和序列化
16、ReferenceCountExchangeClient 在 ExchangeClient 的基础上增加了引用计数,在 ExchangeClient 实现共享时提供引用计数,可以为决策关闭 ExchangeClient 时提供依据;
17-18、HeaderExchangeClient 是 Client 的一个装饰者模式增强类,为 Client 增加了心跳逻辑;
19-20、 是 NettyClient 的发送逻辑,委托父类的实现
21、是 NettyClient 的发送逻辑最终委托给 NettyChannel 来实现
22、最终委托给 netty 的 channel.writeAndFlush 实现网络数据的发出,编码和序列化就是在这个过程中执行的,这个就牵涉到netty的使用了不过多解释