❶:客户端发送数据,这里触发执行netty pipeline的outbound事件,执行顺序TailContext->NettyClientHandler->InternalEncoder->InternalDecoder->HeadContext,其中在TailContext#writeAndFlush,封装余下pipeline及构造WriteAndFlushTask并添加到IO线程(netty work线程)的队列taskQueue,然后业务线程发送执行完毕。同时由于IO线程对象NioEventLoop自旋,执行runAllTasks操作从队列taskQueue取出WriteAndFlushTask任务执行,先执行write,再执行flush,因此要对应pipeline执行write & flush操作
即NettyClientHandler->InternalEncoder->InternalDecoder->HeadContext 先执行write操作,再执行flush操作
最后在HeadContext的write和flush操作内调用unsafe对象即NioSocketChannel$NioSocketChannelUnsafe(AbstractChannel.AbstractUnsafe).write(Object msg, ChannelPromise promise) & flush(),其中write是把数据写到缓冲区,flush是发送数据到网卡
其中在执行NettyClientHandler的write操作时候,还会执行Dubbo channelHandler chain的sent操作,即NettyClient->MultiMessageHandler->HeartbeatHandler->AllChannelHandler->DecodeHandler->HeaderExchangeHandler->DubboProtocol$1的sent操作,钩子扩展,这里并没有实际功能。
NettyClientHandler的个netty channelhandler,持有了dubbo channelhandler chain【NettyClient->MultiMessageHandler->HeartbeatHandler->AllChannelHandler->DecodeHandler->HeaderExchangeHandler->DubboProtocol$1】,即钩子作用。
❷:服务端接收到客户端数据,IO线程对象NioEventLoop自旋,执行processSelectedKeys操作,触发netty pipeline的channelRead事件,执行顺序HeadContext->InternalDecoder->InternalEncoder->NettyServerHandler->TailContext,先解码,再通过NettyServerHandler把解码结果提交给业务线程池处理,提交任务ChannelEventRunnable到业务线程池是由AllChannelHandler实现。
NettyServerHandler是netty channelhandler,持有了dubbo channelhandler chain【NettyServer->MultiMessageHandler->HeartbeatHandler->AllChannelHandler->DecodeHandler->HeaderExchangeHandler->DubboProtocol$1】,
❸:服务端响应客户端,和❶基本相同,也是在TailContext#writeAndFlush进行线程切换,由业务线程切换到IO线程。这里触发的netty pipeline outbound事件,执行顺序【TailContext->NettyServerHandler->InternalEncoder->InternalDecoder->HeadContext】,其中在NettyServerHandler内触发dubbo channelhandler chain的sent操作,实际并无具体功能。
❹:客户端接收服务端响应,和❷基本相同。netty pipeline执行inboud事件,执行顺【HeadContext->InternalDecoder->InternalEncoder->NettyClientHandler->TailContext】,先解码,再通过NettyClientHandler把解码结果提交给业务线程池处理,提交任务ChannelEventRunnable到业务线程池是由AllChannelHandler实现。
注意:从上面看出,dubbo channelhandler chain是一部分在IO线程执行,一部分是被封装到ChannelEventRunnable在业务线程执行。dubbo channelhandler是职责链,不同handler功能不同。
总结这个流程图是为了更好的体会dubbo的整个请求流程,遇到问题参考此图就很容易找到问题,还有就是理解dubbo对于netty的使用,从这个总结中也看出了netty通信开发的固定的套路,1.增加netty channelhandler进行编解码,2.增加自定义netty channelhandler进行IO线程和业务线程的channelhandler就可以了。通常编解码在IO线程执行,业务在业务线程池执行,通信上需要注意到粘包和拆包的处理。
dubbo动态代理类实际例子,方便遇到问题有实例参考分析
//com.alibaba.dubbo.common.bytecode.Wrapper2 package com.alibaba.dubbo.common.bytecode; import com.alibaba.dubbo.common.bytecode.ClassGenerator; import com.alibaba.dubbo.common.bytecode.NoSuchMethodException; import com.alibaba.dubbo.common.bytecode.NoSuchPropertyException; import com.alibaba.dubbo.common.bytecode.Wrapper; import java.lang.reflect.InvocationTargetException; import java.util.Map; import org.pangu.api.ProductService; import org.pangu.dto.ProductDTO; public class Wrapper2 extends Wrapper implements ClassGenerator.DC { public static String[] pns;//PropertyNames public static Map pts;//Propertys public static String[] mns;//MethodNames public static String[] dmns;//DeclaredMethodNames public static Class[] mts0; public static Class[] mts1; public static Class[] mts2; @Override public String[] getPropertyNames() { return pns; } @Override public boolean hasProperty(String name) { return pts.containsKey(name); } public Class getPropertyType(String name) { return (Class) pts.get(name); } @Override public String[] getMethodNames() { return mns; } @Override public String[] getDeclaredMethodNames() { return dmns; } @Override public void setPropertyValue(Object object, String name, Object object2) { try { ProductService productService = (ProductService) object; } catch (Throwable throwable) { throw new IllegalArgumentException(throwable); } throw new NoSuchPropertyException(new StringBuffer().append("Not found property \"").append(name) .append("\" filed or setter method in class org.pangu.api.ProductService.").toString()); } @Override public Object getPropertyValue(Object object, String name) { try { ProductService productService = (ProductService) object; } catch (Throwable throwable) { throw new IllegalArgumentException(throwable); } throw new NoSuchPropertyException(new StringBuffer().append("Not found property \"").append(name) .append("\" filed or setter method in class org.pangu.api.ProductService.").toString()); } public Object invokeMethod(Object object, String name, Class[] classArray, Object[] objectArray) throws InvocationTargetException { ProductService productService; try { productService = (ProductService) object; } catch (Throwable throwable) { throw new IllegalArgumentException(throwable); } try { if ("findProduct".equals(name) && classArray.length == 1 && classArray[0].getName().equals("java.lang.String")) { return productService.findProduct((String) objectArray[0]); } if ("findProduct".equals(name) && classArray.length == 1 && classArray[0].getName().equals("org.pangu.dto.ProductDTO")) { return productService.findProduct((ProductDTO) objectArray[0]); } if ("selectProduct".equals(name) && classArray.length == 1) { return productService.selectProduct((ProductDTO) objectArray[0]); } } catch (Throwable throwable) { throw new InvocationTargetException(throwable); } throw new NoSuchMethodException(new StringBuffer().append("Not found method \"").append(name) .append("\" in class org.pangu.api.ProductService.").toString()); } } dubbo通信重要接口ChannelHandler设计说明从前面分析可以看出,dubbo也有一套Channel、ChannelHandler,netty也有Channel、ChannelHandler,而且和netty定义的同名。两者区别是什么呢?
netty Channel是对网络通道的抽象,netty ChannelHandler是对Channel的处理器。