netty里面最重要的应该是ChannelHandler,这个里面也是用户编程直接打交道的接口,也是串行于ChannelPipeLine里面执行相应的业务逻辑。
从类结构来看,一个handler应该有一个ChannelHandlerContext,ChannelHandler是处在上层的一个标识接口,下面有两个接口分别来处理Upstream event和一个Downstream event。
ChannelHandler比较好理解,我们重点来看DefaultChannelHandlerContext的实现类。
volatile DefaultChannelHandlerContext next; volatile DefaultChannelHandlerContext prev; private final String name; private final ChannelHandler handler; private final boolean canHandleUpstream; private final boolean canHandleDownstream; private volatile Object attachment;
在这个里面,可以看到有个链表结构,next、prev分别有指向前一个和后一个的HandlerContext,一个是handlerContext的名称,一个是handler就是里面的handler对象,两个变量用来标识是否可以处理upstream和downstream事件的能力,最后一个是attachment,里面放的是handler里面可以传递的一些共享变量信息。
DefaultChannelHandlerContext( DefaultChannelHandlerContext prev, DefaultChannelHandlerContext next, String name, ChannelHandler handler) { if (name == null) { throw new NullPointerException("name"); } if (handler == null) { throw new NullPointerException("handler"); } canHandleUpstream = handler instanceof ChannelUpstreamHandler; canHandleDownstream = handler instanceof ChannelDownstreamHandler; if (!canHandleUpstream && !canHandleDownstream) { throw new IllegalArgumentException( "handler must be either " + ChannelUpstreamHandler.class.getName() + " or " + ChannelDownstreamHandler.class.getName() + '.'); } this.prev = prev; this.next = next; this.name = name; this.handler = handler; }
构造函数也很容易理解,在初始化的时候就将next和prev传递过来了,同时初始化了handler和name,以及根据handler的性质是否可以来处理相关的event。
我们来看sendDownstream和sendUpstream的实现吧。
public void sendDownstream(ChannelEvent e) { DefaultChannelHandlerContext prev = getActualDownstreamContext(this.prev); if (prev == null) { try { getSink().eventSunk(DefaultChannelPipeline.this, e); } catch (Throwable t) { notifyHandlerException(e, t); } } else { DefaultChannelPipeline.this.sendDownstream(prev, e); } }
从这个代码来看,通过getActualDownstreamContext顺着prev链条超前找,找到前一个可以处理downstream的handlerContext,然后开始执行,如果找不到就交给Sink来处理,从这里来看也能体会到一点handler和sink自己的一些关系,作者将这个抽象成两个组件来处理确实比较厉害。
同理我们也可以猜到upstream事件的处理逻辑,找到最后一个handler然后一点一点的处理。
public void sendUpstream(ChannelEvent e) { DefaultChannelHandlerContext next = getActualUpstreamContext(this.next); if (next != null) { DefaultChannelPipeline.this.sendUpstream(next, e); } }