前言:
为了更好地理解本系列文章,需要读者对JAVA NIO和Netty有简单的了解。本节只对Netty中的事件模型进行整体概况,不做源码的具体分析,读者在理解这个模型后,后面的源码分析阶段,就相对容易理解了。
一、Netty中事件流动示意图如下:
在Netty中每一条Channel中都定义了一个ChannelPipeline(默认使用DefaultChannelPipeline)。ChannelPipeline中使用双向链表的方式存储了多个ChannelHandlerContext(默认使用DefaultChannelHandlerContext)。每一个ChannelHandlerContext中都有一个ChannelHandler,用于事件的具体处理逻辑。并且,Netty定义的HeadHandler和TailHandler永远位于链表的两端,开发者自定义的ChannelHandler根据插入顺序位于中间位置。 Netty中所有的操作(如:读、写、连接、异常处理等,可以参考LoggingHandler类中对事件的归纳)都被定义为事件,对每一个事件的处理,根据事件类型要么是从链表的头到尾,要么是链表尾到头的流程。并且Netty对事件模型的处理机制进行了优化,一般一个事件不会经过所有的ChannelHandler,会根据事件的类型跳过一些对该事件不会产生影响的ChannelHandler,但是流程顺序不会改变。
上文提及的ChannelHandler添加方式如下:
处理机制优化代码如下: io.netty.channel.ChannelHandlerMask#isSkippable
private static boolean isSkippable(
final Class<?> handlerType, final String methodName, final Class<?>... paramTypes) throws Exception {
return AccessController.doPrivileged((PrivilegedExceptionAction<Boolean>) () -> {
Method m;
try {
m = handlerType.getMethod(methodName, paramTypes);
} catch (NoSuchMethodException e) {
if (logger.isDebugEnabled()) {
logger.debug(
"Class {} missing method {}, assume we can not skip execution", handlerType, methodName, e);
}
return false;
}
return m.isAnnotationPresent(Skip.class);
});
}
最后附上Netty中对ChannelPipeline的概述图:
* I/O Request
* via {@link Channel} or
* {@link ChannelHandlerContext}
* |
* +---------------------------------------------------+---------------+
* | ChannelPipeline | |
* | \|/ |
* | +---------------------+ +-----------+----------+ |
* | | Inbound Handler N | | Outbound Handler 1 | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ | |
* | | \|/ |
* | +----------+----------+ +-----------+----------+ |
* | | Inbound Handler N-1 | | Outbound Handler 2 | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ . |
* | . . |
* | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
* | [ method call] [method call] |
* | . . |
* | . \|/ |
* | +----------+----------+ +-----------+----------+ |
* | | Inbound Handler 2 | | Outbound Handler M-1 | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ | |
* | | \|/ |
* | +----------+----------+ +-----------+----------+ |
* | | Inbound Handler 1 | | Outbound Handler M | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ | |
* +---------------+-----------------------------------+---------------+
* | \|/
* +---------------+-----------------------------------+---------------+
* | | | |
* | [ Socket.read() ] [ Socket.write() ] |
* | |
* | Netty Internal I/O Threads (Transport Implementation) |
* +-------------------------------------------------------------------+