Netty源码(二)- ChannelPipeline(事件模型)

718 阅读2分钟

前言:

为了更好地理解本系列文章,需要读者对JAVA NIO和Netty有简单的了解。本节只对Netty中的事件模型进行整体概况,不做源码的具体分析,读者在理解这个模型后,后面的源码分析阶段,就相对容易理解了。

一、Netty中事件流动示意图如下:

image.png 在Netty中每一条Channel中都定义了一个ChannelPipeline(默认使用DefaultChannelPipeline)。ChannelPipeline中使用双向链表的方式存储了多个ChannelHandlerContext(默认使用DefaultChannelHandlerContext)。每一个ChannelHandlerContext中都有一个ChannelHandler,用于事件的具体处理逻辑。并且,Netty定义的HeadHandler和TailHandler永远位于链表的两端,开发者自定义的ChannelHandler根据插入顺序位于中间位置。 Netty中所有的操作(如:读、写、连接、异常处理等,可以参考LoggingHandler类中对事件的归纳)都被定义为事件,对每一个事件的处理,根据事件类型要么是从链表的头到尾,要么是链表尾到头的流程。并且Netty对事件模型的处理机制进行了优化,一般一个事件不会经过所有的ChannelHandler,会根据事件的类型跳过一些对该事件不会产生影响的ChannelHandler,但是流程顺序不会改变。

上文提及的ChannelHandler添加方式如下:
image.png

处理机制优化代码如下: 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)            |
 *  +-------------------------------------------------------------------+