四Netty组件类--3ChannelPipeline
四Netty组件类--3ChannelPipeline
17.1 ChannelPipeline功能说明
channePipeline是容器,可以动态编排职责链(职责链中node节点是ChannelHandler包装成的ChannelContextHandler),职责链可以有选择的监听、处理自己关心的事件。
17.1.1 channelPipeline功能说明

channelPipeline实现了ChanneInboundInvoker和ChannelOutboundInvoker,因此channelPipeline中继承了fireXXX(inbound)和XXX(outbound)方法,因此channelPipeline也就有了invoker的作用------实现handler的链式调用,详看[17.5.5 AbstractChannelHandlerContext.fireChannelRead流程](# 17.5.5 AbstractChannelHandlerContext.fireChannelRead流程)。
channelPipeline与channelHandlerContext关系:

从源码的doc介绍中,可以知道pipeline的功能及工作原理如下:
1 channelhandler链,用来处理或者拦截对channel的inbound事件、outbound的操作。而pipeline是实现拦截过滤器的高阶形式,把一个事件event的处理和在pipeline中的相互作用、传递的操作控制权,交给用户;
2 每个channel有一个pipeline,在channel创建时,pipeline自动创建;
3 pipeline中的channelHandler可以处理IO event;并且可以将event传递给下一个channelhandler;此外,channelhandler可以trigger任意的IO event事件。
IO事件的传递或者trigger,是通过channelHandlerContext内的方法实现的,如ChannelHandlerContext.fireChannelRead(Object) and ChannelHandlerContext.write(Object)。(需要fireXXX,或者outbound方法)
//outbound事件
I/O Request
via Channel or
ChannelHandlerContext
|
+---------------------------------------------------+---------------+
| ChannelPipeline | |
| \|/ |
| +----------------------------------------------+----------+ |
| | ChannelHandler N | |
| +----------+-----------------------------------+----------+ |
| /|\ | |
| | \|/ |
| +----------+-----------------------------------+----------+ |
| | ChannelHandler N-1 | |
| +----------+-----------------------------------+----------+ |
| /|\ . |
| . . |
| ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
| [method call] [method call] |
| . . |
| . \|/ |
| +----------+-----------------------------------+----------+ |
| | ChannelHandler 2 | |
| +----------+-----------------------------------+----------+ |
| /|\ | |
| | \|/ |
| +----------+-----------------------------------+----------+ |
| | ChannelHandler 1 | |
| +----------+-----------------------------------+----------+ |
| /|\ | |
+---------------+-----------------------------------+---------------+
| \|/
+---------------+-----------------------------------+---------------+
| | | |
| [ Socket.read() ] [ Socket.write() ] |
| // inbound事件 |
| Netty Internal I/O Threads (Transport Implementation) |
+-------------------------------------------------------------------+
Inbound Event:上表左侧,从底到顶的是inbound事件的传递流向。inbound事件,是channel的状态改变、或者从peer处读取到inbound data,由IO线程触发,然后通知channelHandler并执行相关方法。当inbound事件超出上面pipeline,会丢弃并log。
outbound Event:上表右侧,从顶到底是outbound事件的传递流向,由user的code出发,如write、或者connect的尝试。当event超出pipeline时,会由channel绑定的IO线程处理,IO线程会处理真正的out操作,如SocketChannel.write(ByteBuffer)。
4 event事件的转发通过channelHandlerContext的方法
//Inbound event 传递 methods:
ChannelHandlerContext.fireChannelRegistered()
ChannelHandlerContext.fireChannelActive()
ChannelHandlerContext.fireChannelRead(Object)
ChannelHandlerContext.fireChannelReadComplete()
ChannelHandlerContext.fireExceptionCaught(Throwable)
ChannelHandlerContext.fireUserEventTriggered(Object)
ChannelHandlerContext.fireChannelWritabilityChanged()
ChannelHandlerContext.fireChannelInactive()
// Outbound event 传递 methods:
ChannelHandlerContext.bind(SocketAddress, ChannelPromise)
ChannelHandlerContext.connect(SocketAddress, SocketAddress, ChannelPromise)
ChannelHandlerContext.write(Object, ChannelPromise)
ChannelHandlerContext.flush()
ChannelHandlerContext.read()
ChannelHandlerContext.disconnect(ChannelPromise)
ChannelHandlerContext.close(ChannelPromise)
inbound事件的传递,需要执行channelHandlerContext.fireChanneXXX方法;outbound的传递,需要执行channelHandlerContext的out方法。
5 创建pipeline
需要根据业务需求添加channelhandler,如编解码、以及业务处理代码handler。
如下:
static final EventExecutorGroup group = new DefaultEventExecutorGroup(16);
...
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new MyProtocolDecoder());
pipeline.addLast("encoder", new MyProtocolEncoder());
//addLast中group,指定了执行handler的线程池
//如果业务task是耗时的操作,会阻塞IO线程,需要指定执行业务逻辑的线程池;否则,可以把task交给IO线程,避免线程切换
pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
6 pipeline线程安全
由于netty的线程模型,每个channel以及pipeline绑定一个IO线程,因此保证一个channel上的操作是串行的,所以可以在任意时刻,在pipeline中添加、删除channelHandler。(例如:对于数据敏感的信息,可以在发送信息的时候,添加一个数据加密的handler,在修改后可以删除该handler)
17.1.2 channelPipeline的API

channelPipeline中包括三部分的方法,handler的管理方法、ChannelInboundInvoker方法、ChannelOutboundInvoker方法。
“Channel流水线”,即Channel管道(事件处理链),其主要核心方法包括如下三类。
1 添加类操作:
ChannelPipeline addFirst(String name, ChannelHandler handler)
ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler)
ChannelPipeline addFirst(ChannelHandler… handlers)
ChannelPipeline addFirst(EventExecutorGroup group, ChannelHandler… handlers)
ChannelPipeline addLast(String name, ChannelHandler handler)
ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler)
ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler)
其中省略了addLast、addBefore、addAfter的其他重载方法,模式为addFirst类似。在这里着重讲解一下各个参数的含义。
EventExecutorGroup group
// ChannelHandler执行的线程组EventLoop,如果为空,则ChannelHandler在Channel所注册的EventLoop上执行
String name
// ChannelHandler的名称,DefaultChannelPipeline会避免因重名而修改ChannelHandler的名称。
2 ChannelHandler的增删改查
ChannelPipeline remove(ChannelHandler handler)
ChannelHandler removeFirst()
省略其他API,此类API其实能反映出ChannelPipeline内部是一个双链表结构。
3 入端(inbound)事件传播
ChannelPipeline fireChannelRegistered()
ChannelPipeline fireChannelUnregistered()
ChannelPipeline fireChannelActive()
ChannelPipeline fireChannelInactive()
ChannelPipeline fireExceptionCaught(Throwable cause)
ChannelPipeline fireUserEventTriggered(Object event)
ChannelPipeline fireChannelRead(Object msg)
ChannelPipeline fireChannelReadComplete()
ChannelPipeline fireChannelWritabilityChanged()
inbound主要是触发channel状态的改变---registered、active、read等状态。
不难看出,此类API方法名 fire + ChannelInboundHandler 中的方法。特别注意的是fireChannelRead(Object msg)的参数为通过网络SocketChannel#read一次读取的字节数组(ByteBuf),跟随着事件处理器一步一步的处理。
4 出端(outbound)事件传播
ChannelFuture bind(SocketAddress localAddress)
ChannelFuture connect(SocketAddress remoteAddress)
ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress)
ChannelFuture disconnect()
ChannelFuture close()
ChannelFuture deregister()
ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise)
ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise)
ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise)
ChannelFuture disconnect(ChannelPromise promise)
ChannelFuture close(ChannelPromise promise)
ChannelFuture deregister(ChannelPromise promise)
ChannelPipeline read()
ChannelFuture write(Object msg)
ChannelFuture write(Object msg, ChannelPromise promise)
ChannelPipeline flush()
ChannelFuture writeAndFlush(Object msg, ChannelPromise promise)
ChannelFuture writeAndFlush(Object msg)
ChannelOutboundHandler的方法,是业务中的程序所调用的方法,有bind、connect、close、read、write、writeAndFlush的操作。
17.1.3 DefaultChannelPipeline
final class DefaultChannelPipeline implements ChannelPipeline {
//pipeline所属的channel
final AbstractChannel channel;
//pipeline中的头尾节点信息
final AbstractChannelHandlerContext head;
final AbstractChannelHandlerContext tail;
//
private Map<EventExecutorGroup, ChannelHandlerInvoker> childInvokers;
}
17.1.3.1 PendingHandlerCallback(DefaultChannelPipeline内部类)
这个类,是DefaultChannelPipeline内部类,当将channelhandler新添加入context后,需要执行context.add---》并执行handler.add方法后,pipeline上添加的handlerContext(包裹handler处理器)才能处理Netty的事件。
PendingHandlerCallback是需要执行add的handlerContext的包装类,并代表需要执行add的任务。pendingTask会在DefaultChannelPipeline中,以链的形式存在,并持有task链的head---
private PendingHandlerCallback pendingHandlerCallbackHead;
当defaultChannelPipeline.addLast时,
pipeline中add(handler)逻辑:
synchronized (pipeline) {
1 handler--》创建对应的context对象,并将context加入pipeline的handlercontext的处理链中;
2 如果channel是否注册在nioeventloop上
2.1 如果没有注册:
将ctx设置为ADDPENDING状态,
//TAG1.2.1.1 callHandlerCallbackLater,将当前newCtx加入HandlerCallbackLater的task任务中,一旦channel注册,就执行ChannelHandler.handlerAdded
2.2 如果注册过
2.2.1 当前线程不是eventloop中线程
//TAG1.2.1.2 callHandlerAddedInEventLoop 在eventloop.executor.execute()中执行callHandlerAdded0--执行handler.add操作
}
3 如果当前线程是eventloop绑定的,那么操作pipeline是线程安全,不在synchronized (pipeline)中执行
直接//TAG1.2.1.3 callHandlerAdded0,执行handler.add操作
详细的执行逻辑,详看[TAG1.2.1 ChannelPipeline.addLast](#TAG1.2.1 ChannelPipeline.addLast)
DefaultChannelPipeline
private PendingHandlerCallback pendingHandlerCallbackHead;
private abstract static class PendingHandlerCallback implements Runnable {
final AbstractChannelHandlerContext ctx;
PendingHandlerCallback next;
PendingHandlerCallback(AbstractChannelHandlerContext ctx) {
//该对象是pipeline的AbstractChannelHandlerContext包装类
this.ctx = ctx;
}
abstract void execute();
}
//PendingHandlerCallback的实现类------add添加handler到pipeline的task类
private final class PendingHandlerAddedTask extends PendingHandlerCallback {
PendingHandlerAddedTask(AbstractChannelHandlerContext ctx) {
super(ctx);
}
@Override
public void run() {
callHandlerAdded0(ctx);
}
@Override
void execute() {
//获取AbstractChannelHandlerContext绑定的NioEventLoop对象
EventExecutor executor = ctx.executor();
if (executor.inEventLoop()) {
//TAG1
//调用-添加handler的操作
callHandlerAdded0(ctx);
} else {
try {
executor.execute(this);
} catch (RejectedExecutionException e) {
if (logger.isWarnEnabled()) {
logger.warn(
"Can't invoke handlerAdded() as the EventExecutor {} rejected it, removing handler {}.",
executor, ctx.name(), e);
}
atomicRemoveFromHandlerList(ctx);
ctx.setRemoved();
}
}
}
}
//TAG1
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
//TAG2
//调用AbstractChannelHandlerContext的handleradd方法
ctx.callHandlerAdded();
} catch (Throwable t) {
boolean removed = false;
try {
atomicRemoveFromHandlerList(ctx);
ctx.callHandlerRemoved();
removed = true;
} catch (Throwable t2) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to remove a handler: " + ctx.name(), t2);
}
}
if (removed) {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() +
".handlerAdded() has thrown an exception; removed.", t));
} else {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() +
".handlerAdded() has thrown an exception; also failed to remove.", t));
}
}
}
17.2 ChannelPipeline事件传播(todo)
inbound事件传播同headContext开始,沿着next指针传播;outbound事件传播从tailContext开始,沿着prev指针向前传播。

浙公网安备 33010602011771号