概述
对于一个请求,可能会需要很多的处理逻辑,如果把所有的处理逻辑都放在一个ChannelHandler中,那么代码会十分的臃肿,因此需要把逻辑放在不同的ChannelHandler中实现面向对象的单一职责原则。Netty使用责任链模式把负责不同逻辑的ChannelHandler组合在一起,ChannelPipeline就是ChannelHandler的容器,每一个新建的Channel,Netty都会自动为之分配一个新的ChannelPipeline,这种分配是自动的,且这种绑定在netty整个生命周期中是永久性的。ChannelPipeline会负责Channel所有事件的处理。
ChannelPipeline会按照相反的顺序调用ChannelHandler处理入栈和出栈事件。
源码
addBefor
把名称为name的handler添加到baseName的前面,调用了一个重载的方法。
@Override public final ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler) { return addBefore(null, baseName, name, handler); }
group传入的是null,不需要考虑。
- 首先注意到整个代码用synchronized包裹起来,说明这是ChannelPipe是一个线程安全的对象,这是因为netty允许在运行时候动态修改ChannelPipe的内容,那么就存在修改线程和正常运行线程同时访问ChannelPipe的情况,需要使用synchronized来避免潜在的线程安全问题。
- checkMultiplicity判断handler是否可以共享,如果handler已经添加且不可共享,抛出异常。
- 对handler的名称进行检查(filterName),如果名称重复抛出异常,如果name为Null则生成一个name。
- 调用getContextOrDie从容器中找到baseName的handler,如这个方法名字暗示,如果没有找到就抛出异常(OrDie)。
- 新建ChannelHandlerContext作为新handler的上下文,并添加到Pipeline里,pipeline说白了就是个双向链表,添加的方法也很简单,ChannelPipeline持有双向链表的头节点和尾节点。
@Override public final ChannelPipeline addBefore( EventExecutorGroup group, String baseName, String name, ChannelHandler handler) { final AbstractChannelHandlerContext newCtx; final AbstractChannelHandlerContext ctx; synchronized (this) { checkMultiplicity(handler); name = filterName(name, handler); ctx = getContextOrDie(baseName); newCtx = newContext(group, name, handler); addBefore0(ctx, newCtx); // If the registered is false it means that the channel was not registered on an eventloop yet. // In this case we add the context to the pipeline and add a task that will call // ChannelHandler.handlerAdded(...) once the channel is registered. if (!registered) { newCtx.setAddPending(); callHandlerCallbackLater(newCtx, true); return this; } EventExecutor executor = newCtx.executor(); if (!executor.inEventLoop()) { newCtx.setAddPending(); executor.execute(new Runnable() { @Override public void run() { callHandlerAdded0(newCtx); } }); return this; } } callHandlerAdded0(newCtx); return this; }