接上篇博客《Dubbo源码深度解析(三)》,上篇博文,主要讲的是DubboBootstrap#start()方法中调用到的其他方法,以及讲到ServiceConfig#export()方法的调用链路。其中讲到最核心的方法为ServiceConfig#doExportUrlsFor1Protocol(),还没讲完,今天接着讲,上篇讲到了这里:
看看PROXY_FACTORY#getInvoker()方法,发现ProxyFactory也是由ExtensionLoader加载的,代码如下:
看看ProxyFactory接口,代码如下:
看看ProxyFactory的实现类,代码如下:
发现这三个实现类均没有被@Adaptive注解修饰,因此最终会调用到ExtensionLoader#createAdaptiveExtensionClass(),动态生成ProxyFactory接口实现的字节码对象,看看该方法:
看看AdaptiveClassCodeGenerator#generate()方法,代码如下:
看看AdaptiveClassCodeGenerator#generateMethod()方法,代码如下:
看看最后生成的ProxyFactory的实现类,实现类如下:
因此,调用PROXY_FACTORY#getInvoker()方法,实际上是调用ProxyFactory$Adaptive#getInvoker()方法,如果传入的url中,proxy属性(可以在@DubboService注解上指定)不为空,则获取属性值,如果为空,则用默认的值"javassist",最终调用ExtensionLoader#getExtensionLoader(ProxyFactory.class).getExtension("javassist")方法,获取具体的实现类,而名字叫"javassist"的ProxyFactory接口的实现类,是JavassistProxyFactory,最终调用的是JavassistProxyFactory#getInvoker()方法,代码如下:
由上图可知,Wrapper#getWrapper()方法也很重要,看看该方法,代码如下:
调用Wrapper#getWrapper()方法,传入的接口是HelloService.class,最终生成的返回的Wrapper对象实际上是继承了Wrapper(它是抽象类),Wrapper0,大概长这个样子,代码如下:
看看HelloService接口,代码如下:
到这里很清晰了:调用Wrapper#getWrapper()方法,最终生成的是Wrapper类的实现类的对象,实现类的命名为:
生成的实现类,最终会缓存到Wrapper的WRAPPER_MAP属性中,代码如下:
最终调用JavassistProxyFactory#getInvoker()方法,返回的是AbstractProxyInvoker的实现类,代码如下:
再回到ServiceConfig#doExportUrlsFor1Protocol()方法中,调用PROXY_FACTORY.getInvoker()方法的地方,代码如下:
可以知道,返回的invoker对象是AbstractProxyInvoker的子类,又对invoker做了一层包装,即DelegateProviderMetaDataInvoker对象,调用其有参构造,传入invoker对象。再调用PROTOCOL#export()方法,传入DelegateProviderMetaDataInvoker对象,而PROTOCOL属性又和PROXY_FACTORY属性类似,如下:
看看Protocol接口,代码如下:
发现Protocol接口的子类也都没有被@Adaptive注解修饰,因此也会动态生成Protocol接口的实现类,代码如下(截取部分):
最终也是寻找一个name叫"registry"的Protocol接口的实现类,看看org.apache.dubbo.rpc.Protocol文件的内容,可知实现类是InterfaceCompatibleRegistryProtocol
这个说法对,但不全对,最终肯定InterfaceCompatibleRegistryProtocol,还记得我在《Dubbo源码深度解析(二)》中讲Dubbo的SPI机制吗?里面提到了包装类型,这里就用到了,先看看Protocol接口的的实现类,如下:
看看其中一个包装类,如ProtocolFilterWrapper,代码如下:
再回过头看看Protocol$Adaptive#export()方法,最终调用的是 Protocol extension = (Protocol) ExtensionLoader#getExtensionLoader(Protocol.class).getExtension("registry")方法,代码如下:
上图中的instance对象肯定是InterfaceCompatibleRegistryProtocol对象,但是还调用了ExtensionLoader#injectExtension()方法,并传入了instance对象,实际上是给instance对象进行属性注入,看看该方法,代码如下:
再看看排序,即WrapperComparator.COMPARATOR类,代码如下:
可只是按照正序排列,也就是order越小,在越靠前,解析到了两个包装类,分别是ProtocolFilterWrapper和ProtocolListenerWrapper,代码如下:
因此,缓存的包装类的顺序也是ProtocolFilterWrapper、ProtocolListenerWrapper,但是又调用了Collections.reverse()方法,因此最终的顺序是:ProtocolListenerWrapper、ProtocolFilterWrapper(先顺序排列再反转,相当于直接是倒序排),再进行循环,代码如下:
因此ProtocolFilterWrapper对像的protocol属性是ProtocolListenerWrapper对象,ProtocolListenerWrapper对象的protocol属性是InterfaceCompatibleRegistryProtocol对象,而InterfaceCompatibleRegistryProtocol对象的protocol属性是Protocol$Adaptive,打断点验证如下:
因此,最终调用的是ProtocolFilterWrapper#export()方法,代码如下:
看看RegistryProtocol#doLocalExport()方法,代码如下:
而这里传入的参数protocol属性在前面说过,实际上是Protocol$Adaptive对象,相当于调用的又是Protocol$Adaptive#export()方法,但是此时传入的url为 providerUrl,跟之前的不太一样,由上面打断点可知,providerUrl的protocol属性为"dubbo",因此最终得到的结果对象为:ProtocolFilterWrapper对像,而ProtocolFilterWrapper对像的protocol属性是ProtocolListenerWrapper对象,ProtocolListenerWrapper对象的protocol属性是DubboProtocol,打断点验证,结果如下:
前面两个对象的export()方法就不看了,直接看DubboProtocol#export()方法,代码如下:
可知最终创建服务器是通过Exchangers#bind()方法,传入url和requestHandler,而requestHandler则是DubboProtocol的内部类对象,截取部分代码如下:
看看Exchangers#bind()方法,代码如下:
这里又涉及到SPI,默认的实现类名为"header",这里就不在多过解释,实现类就是HeaderExchanger。最终,调用的是HeaderExchanger#bind()方法,代码如下:
看看Transporters#bind()方法,代码如下:
又涉及到SPI机制,看看Transporter接口,代码如下:
因此,直接看NettyTransporter#bind()方法,代码如下:
上图中传入的handler属性是DecodeHandler对象,DecodeHandler对象的handler属性为HeaderExchangeHandler对象,而HeaderExchangeHandler对象的handler属性为DubboProtocol#ExchangeHandlerAdapter对象,断点验证,结果如下:
看看父类的有参构造方法,涉及到赋初始值或者默认值,代码如下:
再看看AbstractServer#doOpen()方法,代码如下:
重点看看NettyServer#doOpen()方法,代码如下:
其中,bootstrap.bind()方法是绑定ip/port,channelFuture.syncUninterruptibly()方法一个同步方法,阻塞主线程,避免程序跑完直接就结束了。
这块就是Netty Server启动的核心,也是固定写法,任何一个框架,使用Netty作为其通讯框架,大概都是这样写,没什么好讲的,如果对 Netty框架感兴趣,不妨看我写的这篇博客《Netty源码深度解析》,里面对Netty原理有详细的介绍。我假设你对Netty比较熟,看到上面这块代码,我相信你会毫不犹豫的看这个类:NettyServerHandler,它是处理客户端的连接、请求、响应、断开连接的核心类。因此直接看这个类即可。
① 如果此时有一个客户端发起了连接,连接成功,调用NettyServerHandler#channelActive()方法;
② 客户端发来请求,调用NettyServerHandler#channelRead()方法;
③ 客户端断开连接,调用NettyServerHandler#channelInactive()方法;
④ 向客户端响应,调用NettyServerHandler#write()方法;
重点②④,先看看NettyServerHandler#channelRead()方法,代码如下:
到这里,其实我也不太确定应该是走if逻辑,还是else逻辑,主要是 request.isTwoWay() 不太懂。其实客户端发过来的请求,不是先到NettyServerHandler,之前不是提到过编码、解码吗?如果是客户端发过来的请求,在客户端放已经对请求做过编码,因此服务端接收情请求,需要进行解码。而且客户端发过来的数据,肯定也是二进制的,因此需要处理,因为到NettyServerHandler这边,接收到的,就变成了 Object message,而不是byte[] message,更加可以确定解码类是将接收到的二进制数据转成了 Object message,并且可能还会涉及到粘包拆包等,OK,看看Dubbo是怎么做的,直接看InternalDecoder#decode()方法,代码如下:
codec属性实际上是在这里赋值的,如下:
可以知道,最终调用到DubboCodec#decode()方法,实际上DubboCodec没有decode()方法,而是在其父类中实现的,即调用ExchangeCodec#decode()方法,代码如下:
这里可以打断点看看,结果如下:
很明显,这里的Request的 twoWay属性是在客户端设置的,并放在了请求头中,如果远程调用需要服务端响应结果则为true;不需要响应则为 false。而Request的 mData属性为DecodeableRpcInvocation对象。再回到HeaderExchangeHandler#received()方法,代码如下: