5. Netty源码分析之ChannelPipeline 和 ChannelHanler
前言:ChannelPipeline和ChannelHandler是类似于Spring拦截器的一种实现,数据在pipeline中传播,每个ChannelHandler处理自己感兴趣的部分。
一、ChannelPipeline
ChannelPipeline是ChannelHandler的容器,负责ChannelHandler的管理和事件拦截及调度。
1. ChannelPipeline的事件处理
1. 读操作(InBound):NioEventLoop调用ChannelPipeline的fireChannelRead(..)方法,将消息传输到ChannelPipeline中。Channelhandler处理流程:HeadHandler -> ChannelHandler1 -> .. -> ChannelHandlerN -> TailHandler
2. 写操作(OutBound):调用ChannelHandlerContext的write方法发送消息,经过handler处理后,最终被添加到消息发送缓冲区等待刷新和发送。ChannelHandler处理流程:TailHandler -> ChannelHandlerN -> ... -> ChannelHandler1 -> HeadHandler
这里提到了InBound 和 OutBound,顾名思义,InBound就是指进来,例如read、accept这些,都是IO操作往内部方向进行的;OutBound就是指出去,例如connect、write、flush这些,都是IO操作往外部方向进行的。
2. ChannelPipeline源码分析
ChannelPipeline实际上是一个ChannelHandler管理容器,它的内部维护了一个ChannelHandler的链表和迭代器,可以方便的增删改查ChannelHandler。
我们看一下addBefore方法,这里先后校验了handler不允许多个ChannelPipeline共享、handlerName不能重复、基准handler不能为null,最后把新增的handler放在基准handler之前,最后触发handlerAdded事件。
public final ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler) { return addBefore(null, baseName, name, handler); } public final ChannelPipeline addBefore(EventExecutorGroup group, String baseName, String name, ChannelHandler handler) { final AbstractChannelHandlerContext newCtx; final AbstractChannelHandlerContext ctx; synchronized (this) { //Channdler不允许多个ChannelPipeline共享 checkMultiplicity(handler); // 1. 如果name为空则生成一个name,2.name不允许重复 name = filterName(name, handler); // 根据basic查询要插入到哪个Handler之前,如果不存在,则抛异常 ctx = getContextOrDie(baseName); // 创建DefaultChannelHandlerContext对象 newCtx = newContext(group, name, handler); // 把它加在ctx前面,就是简单的链表插入操作 addBefore0(ctx, newCtx); // 当注册暂未成功时,添加一个handlerAdded任务,当注册成功时调用 if (!registered) { newCtx.setAddPending(); callHandlerCallbackLater(newCtx, true); return this; } // 如果当前线程不是EventLoop线程,则放进EventLoop队列中执行handlerAdded EventExecutor executor = newCtx.executor(); if (!executor.inEventLoop()) { callHandlerAddedInEventLoop(newCtx, executor); return this; } } // 执行handlerAdded callHandlerAdded0(newCtx); return this; } private static void addBefore0(AbstractChannelHandlerContext ctx, AbstractChannelHandlerContext newCtx) { newCtx.prev = ctx.prev; newCtx.next = ctx; ctx.prev.next = newCtx; ctx.prev = newCtx; }
二、ChannelHandler
ChannelHandler类似于Spring的拦截器,负责对IO事件或IO操作进行拦截和处理,它可以选择性的拦截和处理自己感兴趣的事件,也可以透传和终止事件的传递。
ChannelHandler的实现类很多,这里主要说一下ChannelHandlerAdapter。
对于大多数的ChannelHandler而言,都会选择性的拦截自己感兴趣的事件,如果直接实现ChannelHandler,就需要写过多与自己无关的方法。而2ChannelHandlerAdapter实现了ChannelHandler所有的方法,但是所有的实现都是透传,我们只需要继承ChannelHandlerAdapter,覆写自己感兴趣的事件即可。