前面分析过ChannelPipeline的定义,以及它的集成体系,这篇文章深入一些,分写一个它的实现类DefaultChannelPipeline,它直接实现了ChannelPipeline接口。。。
我们首先来看它的一些重要的属性:
final Channel channel; //当前pipeline所属的channel //head和tail都是handler上下文,但是不同的是head它包含的是一个outboundhandler,同时也是operationhanderl //而tail包含的是一个inboundhandler,同时也是一个stathandler final DefaultChannelHandlerContext head; final DefaultChannelHandlerContext tail; private final Map<String, DefaultChannelHandlerContext> name2ctx = new HashMap<String, DefaultChannelHandlerContext>(4); //用于保存所有的handlercontext与name之间的关系其实这些属性基本上都能知道是干嘛的,首先channel保存的是当前pipeline所依附的channel,
然后这里的head与tail都是handlercontext,从名字就会知道他们会用来构成一个链,具体的待会从构造函数中就能知道它们用来干嘛了。。。
然后还有一个map用来存储名字与handler之间的关系。。。。
接下来我们来看它的构造函数:
public DefaultChannelPipeline(Channel channel) { if (channel == null) { throw new NullPointerException("channel"); } this.channel = channel; //为所属的channel赋值 TailHandler tailHandler = new TailHandler(); //构造尾handler,它是一个inboundhandler,同时当然也是stathandler了 tail = new DefaultChannelHandlerContext(this, generateName(tailHandler), tailHandler); HeadHandler headHandler; //接下来开始构造headhandler,它是一个outboundhandler,也就是一个operationhandler switch (channel.metadata().bufferType()) { case BYTE: //operationhandler需要用channel对象的unsafe对象来构造 headHandler = new ByteHeadHandler(channel.unsafe()); break; case MESSAGE: headHandler = new MessageHeadHandler(channel.unsafe()); break; default: throw new Error("unknown buffer type: " + channel.metadata().bufferType()); } head = new DefaultChannelHandlerContext(this, generateName(headHandler), headHandler); //将他们构成链表 head.next = tail; tail.prev = head; }还是相对比较简单,首先是为channel属性赋值,接着初始化head与tail属性,
这里需要预先预习一下两种handler,inboundhandler与outboundhandler,同时inboundhandler实现了stathandler接口,outboundhandler实现了operationhandler接口,说白了inboundhandler用来处理读进来的数据,而outboundhandler用来具体对外的数据操作。。。
这里head将最终包含一个outboundhandler,而tail将最终包含一个inboundhandler。。。
而且最终handler的调用方式是:
(1)对于已经读取的数据需要处理,将会从head开始向下遍历,找到第一个inboundhandler,然后将数据保存到它的buffer,然后由它来处理。。。
(2)对于需要进行对外的操作,那么将会从tail开始,向上遍历,找到第一个outboundhandler,然后由它来处理。。。
我们首先来看内部类TailHandler的实现:
// A special catch-all handler that handles both bytes and messages. static final class TailHandler implements ChannelInboundHandler { final ByteBuf byteSink = Unpooled.buffer(0); final MessageBuf<Object> msgSink = Unpooled.messageBuffer(0); @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { } @Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { } @Override public void channelReadSuspended(ChannelHandlerContext ctx) throws Exception { } @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { logger.warn( "An exceptionCaught() event was fired, and it reached at the tail of the pipeline. " + "It usually means the last handler in the pipeline did not handle the exception.", cause); } @Override public Buf newInboundBuffer(ChannelHandlerContext ctx) throws Exception { throw new Error(); } @Override //数据居然要交到tailhandler来处理了,其实很简单,就是直接丢弃这些数据 public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception { int byteSinkSize = byteSink.readableBytes(); if (byteSinkSize != 0) { byteSink.clear(); logger.warn( "Discarded {} inbound byte(s) that reached at the tail of the pipeline. " + "Please check your pipeline configuration.", byteSinkSize); } int msgSinkSize = msgSink.size(); if (msgSinkSize != 0) { MessageBuf<Object> in = msgSink; for (;;) { Object m = in.poll(); if (m == null) { break; } BufUtil.release(m); logger.debug( "Discarded inbound message {} that reached at the tail of the pipeline. " + "Please check your pipeline configuration.", m); } logger.warn( "Discarded {} inbound message(s) that reached at the tail of the pipeline. " + "Please check your pipeline configuration.", msgSinkSize); } } }它直接继承自inboundhandler,因此实现了所有inboundhandler的方法,其实也就实现了inboundBufferUpdated方法,其余的方法都是空的。。。
这是默认的tail包含的handler,因此也就是最后一个inboundhandler,如果最终不得不由这个handler来处理读取进来的数据,那么就是说明在整个pipeline上面根本就没有用户定义的inboundhandler来处理读进来的数据,这个时候进行的操作就是直接将这些读取的数据抛弃掉就好了。。。。
接下来来看内部类HeadHandler的定义:
abstract static class HeadHandler implements ChannelOutboundHandler { protected final Unsafe unsafe; ByteBuf byteSink; MessageBuf<Object> msgSink; boolean initialized; //构造函数,这个时候的unsafe就是channel的unsafe对象 protected HeadHandler(Unsafe unsafe) { this.unsafe = unsafe; } void init(ChannelHandlerContext ctx) { assert !initialized; switch (ctx.channel().metadata().bufferType()) { case BYTE: byteSink = ctx.alloc().ioBuffer(); msgSink = Unpooled.messageBuffer(0); break; case MESSAGE: byteSink = Unpooled.buffer(0); msgSink = Unpooled.messageBuffer(); break; default: throw new Error(); } } @Override public final void handlerAdded(ChannelHandlerContext ctx) throws Exception { // NOOP } @Override public final void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // NOOP } @Override public final void bind( ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception { unsafe.bind(localAddress, promise); } @Override public final void connect( ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception { unsafe.connect(remoteAddress, localAddress, promise); } @Override public final void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { unsafe.disconnect(promise); } @Override public final void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { unsafe.close(promise); } @Override public final void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { unsafe.deregister(promise); } @Override public final void read(ChannelHandlerContext ctx) { unsafe.beginRead(); } @Override public final void sendFile( ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception { unsafe.sendFile(region, promise); } @Override public final Buf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception { throw new Error(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.fireExceptionCaught(cause); } }它是一个抽象类,因为需要分为两种,基于byte类型的以及基于message类型的。。。
另外我们可以看到一个unsafe对象,其实这个就是当前所属的channel的unsafe对象,对于实际的操作,例如connect,bind等,其实都是基于这个对象来实现的。。。。
对于它的子类,ByteHeadHandler和MessageHeadHandler,他们具体实现了flush方法,用于发送数据,其实数白了最后总还是用unsafe的flush方法来实现的...
看到这里,也能看出,对于outboundhandler不一定需要用户自定义也可以,因为默认的head将会按照channel的unsafe对象将他们发送出去,但是inboundhandler就必须自己定义了。。。。
这里我们来具体分析一个方法:fireInboundBufferUpdated,它是在事件循环中,通过channel的unsafe对象读取到数据后,将会调用的方法,表示已经有数据已经读取了,然后触发inboundhandler来处理这些数据,在DefaultChannelPipeline中这个方法的实现很简单:
//当从nio的channel中读取了数据之后会调用这个方法,最终会激活handler链上的第一个inboundhandler的inboundBufferUpdated方法来处理这些数据 public ChannelPipeline fireInboundBufferUpdated() { head.fireInboundBufferUpdated(); return this; }说白了就是调用headhandler的context的fireInboundBufferUpdated方法(headhandler是一个outboundhandler),那么我们接下来来看看DefaultChannelHandlerContext中该方法的定义吧:
@Override //当已经有数据从nio的channel中读取进来的时候,会调用该方法,用于处理读取进来的数据 public ChannelHandlerContext fireInboundBufferUpdated() { EventExecutor executor = executor(); //用于获取执行代码的executor,其实一般情况下就是当前channel所属的eventLoop if (executor.inEventLoop()) { //如果executor就是当前的eventLoop,那么就直接执行好了否则的话需要向executor提交任务 fireInboundBufferUpdated0(findContextInbound()); } else { Runnable task = fireInboundBufferUpdated0Task; if (task == null) { fireInboundBufferUpdated0Task = task = new Runnable() { @Override public void run() { fireInboundBufferUpdated0(findContextInbound()); } }; } executor.execute(task); } return this; }实现首先是判断当前的executor的线程是否就是当前的执行线程,其实一般情况下都是的,也就是当前channel所属的eventLoop,除非为当前的handler指定了额外的executor,如果有额外的executor的话,那么就需要通过task的方法来执行了。。。这里在具体的执行之前先调用了findContextInbound方法来找到第一个inboundhandler的context,我们来看看该方法的定义吧:
} //headhandler的context会调用该方法,用于向下寻找,找到第一个inboundhandler的context private DefaultChannelHandlerContext findContextInbound() { DefaultChannelHandlerContext ctx = this; do { ctx = ctx.next; } while (!(ctx.handler() instanceof ChannelStateHandler)); return ctx; }这里就能看出,对于读取进来的数据,handler是从head到tail执行的顺序了吧、、、
好了接下来来看fireInboundBufferUpdated0方法:
private void fireInboundBufferUpdated0(final DefaultChannelHandlerContext next) { //handler的buffer之间的联系 feedNextInBridge(); // This comparison is safe because this method is always executed from the executor. if (next.executor == executor) { //有可能找到的第一个inboundhandler的executor不是当前这个executor,不过一般还是当前channel注册到的eventLoop next.invokeInboundBufferUpdated(); //这里说白了就是调用具体的inboundhandler的inboundBufferUpdated方法 } else { Runnable task = next.invokeInboundBufferUpdatedTask; if (task == null) { next.invokeInboundBufferUpdatedTask = task = new Runnable() { @Override public void run() { next.invokeInboundBufferUpdated(); } }; } next.executor().execute(task); } }先刷新了bridge,接着还是判断了executor,最后在调用invokeInboundBufferUpdated方法,来看它的定义:
//具体调用inboundhandler的inboundBufferUpdated方法来处理读进来的数据 private void invokeInboundBufferUpdated() { if (isInboundFreed()) { return; } ChannelStateHandler handler = (ChannelStateHandler) handler(); if (handler instanceof ChannelInboundHandler) { for (;;) { try { boolean flushedAll = flushInboundBridge(); handler.inboundBufferUpdated(this); //调用inboundBufferUpdated函数来处理读进来的数据 if (flushedAll) { break; } } catch (Throwable t) { notifyHandlerException(t); break; } finally { if (handler instanceof ChannelInboundByteHandler && !isInboundFreed()) { try { ((ChannelInboundByteHandler) handler).discardInboundReadBytes(this); } catch (Throwable t) { notifyHandlerException(t); } } freeHandlerBuffersAfterRemoval(); } } } else { try { handler.inboundBufferUpdated(this); } catch (Throwable t) { notifyHandlerException(t); } } }这里调用了inboundhandler的inboundBufferUpdated方法,这个用过netty的就应该很清楚了吧。。。
好了,对于真个数据进来的处理流程就差不了。。。好像也不是说的太细,而且有一些细节我也没有搞的太清楚,例如bridge,不过以后补上吧。。。