Netty源码_ChannelPipeline和ChannelHandlerContext详解

一. ChannelPipeline 接口

1.1 介绍

ChannelPipeline 相当于 ChannelHandler 的集合,用于处理或拦截Channel的入站事件和出站操作。

  • ChannelPipeline实现了拦截过滤器模式的高级形式,让用户完全控制事件的处理方式以及管道中的ChannelHandler如何相互交互。
  • 每个Channel都有自己独有的管道ChannelPipeline,在创建新通道时自动创建。

这里就有两个问题:

  1. ChannelPipeline 是如何管理 ChannelHandler 集合?
  2. ChannelHandler 集合是如何处理I/O事件?

1.1.1 管理ChannelHandler 集合

ChannelPipeline 管理ChannelHandler 集合,是利用 ChannelHandler 创建一个上下文对象 ChannelHandlerContext, 而ChannelPipeline 存储的就是这个上下文对象。
这个 ChannelHandlerContext 对象下一节将重点讲解。

1.1.2 流程图

ChannelPipeline 管理的 ChannelHandler 集合处理I/O事件的流程图如下:


                                                                                                 |
    +---------------------------------------------------+---------------+
    |                           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)            |
    +-------------------------------------------------------------------+

可以看出 ChannelPipeline将管理的 ChannelHandler 分为两种:

  • ChannelInboundHandler 处理入站事件
    • 入站事件是被动接收事件,例如接收远端数据,通道注册成功,通道变的活跃等等。
    • 入站事件流向是从 ChannelPipeline 管理的 ChannelInboundHandler 列表头到尾。因为入站事件一般都是从远端发送过来,所以流向是从头到尾。
    • 采用拦截器的模式,由ChannelInboundHandler 决定是否处理列表中的下一个 ChannelInboundHandler
  • ChannelOutboundHandler 处理出站事件
    • 出站事件是主动触发事件,例如绑定,注册,连接,断开,写入等等。
    • 出站事件流向是从 ChannelPipeline 管理的 ChannelOutboundHandler 列表尾到头。因为出站事件最后要发送到远端,所以从尾到头。
    • 采用拦截器的模式,由ChannelInboundHandler 决定是否处理列表中的下一个 ChannelInboundHandler (因为是从尾到头,这里的下一个,在列表中其实是上一个)。

1.2 源码

public interface ChannelPipeline
        extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable> {

    /**
     * 在这个管道ChannelPipeline的开头插入给定的ChannelHandler。
     *
     * @throws IllegalArgumentException
     *         if there's an entry with the same name already in the pipeline
     * @throws NullPointerException
     *         if the specified handler is {@code null}
     */
    ChannelPipeline addFirst(String name, ChannelHandler handler);

    /**
     * 在这个管道ChannelPipeline的开头插入给定的ChannelHandler。
     *
     * @throws IllegalArgumentException
     *         if there's an entry with the same name already in the pipeline
     * @throws NullPointerException
     *         if the specified handler is {@code null}
     */
    ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler);

    /**
     * 在管道的最后追加给定的 ChannelHandler。
     *
     * @throws IllegalArgumentException
     *         if there's an entry with the same name already in the pipeline
     * @throws NullPointerException
     *         if the specified handler is {@code null}
     */
    ChannelPipeline addLast(String name, ChannelHandler handler);

    /**
     * 在管道的最后追加给定的 ChannelHandler。
     *
     * @throws IllegalArgumentException
     *         if there's an entry with the same name already in the pipeline
     * @throws NullPointerException
     *         if the specified handler is {@code null}
     */
    ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler);

    /**
     * 在此管道的现有ChannelHandler(名称是baseName)之前插入ChannelHandler。
     *
     * @throws NoSuchElementException
     *         if there's no such entry with the specified {@code baseName}
     * @throws IllegalArgumentException
     *         if there's an entry with the same name already in the pipeline
     * @throws NullPointerException
     *         if the specified baseName or handler is {@code null}
     */
    ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);

    /**
     * 在此管道的现有ChannelHandler(名称是baseName)之前插入ChannelHandler。
     *
     * @throws NoSuchElementException
     *         if there's no such entry with the specified {@code baseName}
     * @throws IllegalArgumentException
     *         if there's an entry with the same name already in the pipeline
     * @throws NullPointerException
     *         if the specified baseName or handler is {@code null}
     */
    ChannelPipeline addBefore(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);

    /**
     * 在此管道的现有ChannelHandler(名称是baseName)之后插入ChannelHandler。
     *
     * @throws NoSuchElementException
     *         if there's no such entry with the specified {@code baseName}
     * @throws IllegalArgumentException
     *         if there's an entry with the same name already in the pipeline
     * @throws NullPointerException
     *         if the specified baseName or handler is {@code null}
     */
    ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);

    /**
     * 在此管道的现有ChannelHandler(名称是baseName)之后插入ChannelHandler。
     *
     * @throws NoSuchElementException
     *         if there's no such entry with the specified {@code baseName}
     * @throws IllegalArgumentException
     *         if there's an entry with the same name already in the pipeline
     * @throws NullPointerException
     *         if the specified baseName or handler is {@code null}
     */
    ChannelPipeline addAfter(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);

    /**
     * 在这个管道ChannelPipeline的开头插入多个 ChannelHandler。
     */
    ChannelPipeline addFirst(ChannelHandler... handlers);

    /**
     * 在这个管道ChannelPipeline的开头插入多个 ChannelHandler。
     */
    ChannelPipeline addFirst(EventExecutorGroup group, ChannelHandler... handlers);

    /**
     * 在管道的最后追加多个 ChannelHandler。
     */
    ChannelPipeline addLast(ChannelHandler... handlers);

    /**
     * 在管道的最后追加多个 ChannelHandler。
     */
    ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler... handlers);

    /**
     * 从管道中删除指定的 ChannelHandler
     *
     * @throws NoSuchElementException
     *         if there's no such handler in this pipeline
     * @throws NullPointerException
     *         if the specified handler is {@code null}
     */
    ChannelPipeline remove(ChannelHandler handler);

    /**
     * 从管道中删除指定名称的 ChannelHandler
     * 返回被删除的 ChannelHandler 对象
     * @throws NoSuchElementException
     *         if there's no such handler with the specified name in this pipeline
     * @throws NullPointerException
     *         if the specified name is {@code null}
     */
    ChannelHandler remove(String name);

    /**
     * 从管道中删除指定类型的 ChannelHandler
     * 返回被删除的 ChannelHandler 对象
     *
     * @throws NoSuchElementException
     *         if there's no such handler of the specified type in this pipeline
     * @throws NullPointerException
     *         if the specified handler type is {@code null}
     */
     T remove(Class handlerType);

    /**
     * 删除管道中第一个的 ChannelHandler,并返回删除的 ChannelHandler 对象
     * @throws NoSuchElementException
     *         if this pipeline is empty
     */
    ChannelHandler removeFirst();

    /**
     * 删除管道中最后一个的 ChannelHandler,并返回删除的 ChannelHandler 对象
     * @throws NoSuchElementException
     *         if this pipeline is empty
     */
    ChannelHandler removeLast();

    /**
     * 用新的 newHandler 替换该管道中指定老的 oldHandler。
     *
     * @throws NoSuchElementException
     *         if the specified old handler does not exist in this pipeline
     * @throws IllegalArgumentException
     *         if a handler with the specified new name already exists in this
     *         pipeline, except for the handler to be replaced
     * @throws NullPointerException
     *         if the specified old handler or new handler is
     *         {@code null}
     */
    ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);

    /**
     * 用新的 newHandler 替换该管道中指定名称老的 ChannelHandler。
     * 返回被替换老的 ChannelHandler
     *
     * @throws NoSuchElementException
     *         if the handler with the specified old name does not exist in this pipeline
     * @throws IllegalArgumentException
     *         if a handler with the specified new name already exists in this
     *         pipeline, except for the handler to be replaced
     * @throws NullPointerException
     *         if the specified old handler or new handler is
     *         {@code null}
     */
    ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);

    /**
     * 用新的 newHandler 替换该管道中指定类型老的 ChannelHandler。
     * 返回被替换老的 ChannelHandler
     *
     * @throws NoSuchElementException
     *         if the handler of the specified old handler type does not exist
     *         in this pipeline
     * @throws IllegalArgumentException
     *         if a handler with the specified new name already exists in this
     *         pipeline, except for the handler to be replaced
     * @throws NullPointerException
     *         if the specified old handler or new handler is
     *         {@code null}
     */
     T replace(Class oldHandlerType, String newName,
                                         ChannelHandler newHandler);

    /**
     * 返回此管道中的第一个 ChannelHandler。
     * 如果管道为空,那么就返回 null
     */
    ChannelHandler first();

    /**
     * 返回此管道中第一个 ChannelHandler 的上下文对象 ChannelHandlerContext。
     * 如果管道为空,那么就返回 null
     */
    ChannelHandlerContext firstContext();

    /**
     * 返回此管道中的最后一个 ChannelHandler。
     * 如果管道为空,那么就返回 null
     */
    ChannelHandler last();

    /**
     * 返回此管道中最后一个 ChannelHandler 的上下文对象 ChannelHandlerContext。
     * 如果管道为空,那么就返回 null
     */
    ChannelHandlerContext lastContext();

    /**
     * 返回此管道中指定名称的 ChannelHandler。
     */
    ChannelHandler get(String name);

    /**
     * 返回此管道中指定类型的 ChannelHandler。
     */
     T get(Class handlerType);

    /**
     * 返回此管道中指定ChannelHandler的上下文对象ChannelHandlerContext。
     */
    ChannelHandlerContext context(ChannelHandler handler);

    /**
     * 返回此管道中指定名称 ChannelHandler 的上下文对象ChannelHandlerContext。
     */
    ChannelHandlerContext context(String name);

    /**
     * 返回此管道中指定类型 ChannelHandler 的上下文对象ChannelHandlerContext。
     */
    ChannelHandlerContext context(Class handlerType);

    /**
     * 返回此管道依附的通道 Channel。
     */
    Channel channel();

    /**
     * Returns the {@link List} of the handler names.
     * 返回此管道拥有的 ChannelHandler 名称的列表。
     */
    List names();

    /**
     * 返回此管道拥有的 ChannelHandler 集合
     */
    Map toMap();

    // -------   复写来自 ChannelInboundInvoker 中的方法  ---------//
    @Override
    ChannelPipeline fireChannelRegistered();

    @Override
    ChannelPipeline fireChannelUnregistered();

    @Override
    ChannelPipeline fireChannelActive();

    @Override
    ChannelPipeline fireChannelInactive();

    @Override
    ChannelPipeline fireExceptionCaught(Throwable cause);

    @Override
    ChannelPipeline fireUserEventTriggered(Object event);

    @Override
    ChannelPipeline fireChannelRead(Object msg);

    @Override
    ChannelPipeline fireChannelReadComplete();

    @Override
    ChannelPipeline fireChannelWritabilityChanged();

    @Override
    ChannelPipeline flush();
}

不要看 ChannelPipeline 方法很多,其实主要分为两类:

  1. 一类是管理 ChannelHandler 相关方法,比如向管道ChannelPipeline添加,删除,替换,查找 ChannelHandler 方法。
  2. 一类是继承自 ChannelInboundInvokerChannelOutboundInvoker 方法,用于发送入站和出站事件。

1.2.1 管理 ChannelHandler

1.2.1.1 添加

添加到管道 ChannelPipelineChannelHandler都要有一个名字,可以根据这个名字在管道中查找到这个ChannelHandler

   ChannelPipeline addFirst(String name, ChannelHandler handler);
   ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler);

   ChannelPipeline addLast(String name, ChannelHandler handler);
   ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler);
    
   ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);
   ChannelPipeline addBefore(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);
  
   ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);
   ChannelPipeline addAfter(EventExecutorGroup group, String baseName, String name, ChannelHandler handler);

   ChannelPipeline addFirst(ChannelHandler... handlers);
   ChannelPipeline addFirst(EventExecutorGroup group, ChannelHandler... handlers);
   
   ChannelPipeline addLast(ChannelHandler... handlers);
   ChannelPipeline addLast(EventExecutorGroup group, ChannelHandler... handlers);
  • 可以向管道 ChannelPipeline 头或者尾插入一个或者多个ChannelHandler
  • 可以在管道ChannelPipeline中已存在的某个ChannelHandler(通过baseName 查找到) ,之前或者之后插入一个ChannelHandler

你会发现每个添加方法都有多一个 EventExecutorGroup 参数的对应方法,它作用是什么呢?

  • 我们知道通道 Channel 是注册到一个事件轮询器 EventLoop 中,通道所有的IO 事件都是通过在这个事件轮询器中获取。
  • 那么默认情况下,通道 Channel 对应的管道 ChannelPipeline 所管理的 ChannelHandler 也都是在这个事件轮询器中处理的。
  • 这就要求 ChannelHandler不能有太耗时操作,尤其是不能有阻塞操作,这样会导致整个事件轮询器被阻塞,会影响注册到这个事件轮询器所有通道的IO 事件处理,以及这个事件轮询器包含的所有待执行任务和计划任务。
  • 但是我们真的有这个方面的需求怎么办呢? 因此 ChannelPipeline 提供了多一个 EventExecutorGroup 参数的方法,它会将添加的这个 ChannelHandler 的所有方法都放在指定的这个事件执行器组EventExecutorGroup中执行,这样就不会阻塞通道 Channel 对应的事件轮询器。

1.2.1.2 删除

ChannelPipeline remove(ChannelHandler handler);

ChannelHandler remove(String name);

 T remove(Class handlerType);

ChannelHandler removeFirst();

ChannelHandler removeLast();
  • 直接从管道中删除指定的 ChannelHandler 对象
  • 从管道删除指定名称name或者指定类型handlerTypeChannelHandler 对象,并返回它。
  • 删除管道头或者尾的ChannelHandler 对象,并返回它。

1.2.1.3 替换

ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);

ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);

 T replace(Class oldHandlerType, String newName,ChannelHandler newHandler);
  • 用新的 newHandler 替换该管道中指定老的 oldHandler
  • 用新的 newHandler 替换该管道中指定名称oldName或者指定类型oldHandlerType 对应的老 ChannelHandler, 并返回它。

1.2.1.4 查找

ChannelHandler get(String name);
 T get(Class handlerType);

ChannelHandlerContext context(ChannelHandler handler);
ChannelHandlerContext context(String name);
ChannelHandlerContext context(Class handlerType);
  • 根据名字或者类型从管道中查找对应的 ChannelHandler 对象。
  • 根据 ChannelHandler 或者名字或者类型从管道中查找对应的 ChannelHandlerContext 对象。
  • 其实管道ChannelPipeline 存储的是ChannelHandlerContext 对象,它是由 ChannelHandler 对象创建的,可以通过ChannelHandlerContext直接获取ChannelHandler

1.2.1.5 其他方法

ChannelHandler first();
ChannelHandlerContext firstContext();

ChannelHandler last();
ChannelHandlerContext lastContext();

List names();
Map toMap();
  • 获取管道头或者尾的 ChannelHandler 以及 ChannelHandlerContext 对象。
  • 获取管道拥有的 ChannelHandler 名称的列表。
  • 获取此管道拥有的 ChannelHandler 集合。

1.2.2 继承自 ChannelInboundInvokerChannelOutboundInvoker 方法

这两个接口与入站事件处理接口ChannelInboundHandler和出站事件处理接口ChannelOutboundHandler 息息相关。

  • ChannelInboundInvoker 是用来发送入站事件的;
  • ChannelOutboundInvoker 是用来发送出站事件的。

ChannelPipeline 实现中:

  1. ChannelInboundInvoker 发送的入站事件,会直接通过管道管理的 ChannelInboundHandler 列表从头到尾的触发,采用拦截器模式,由 ChannelInboundHandler 决定是否继续调用下一个 ChannelInboundHandler 处理。
  2. ChannelOutboundInvoker 发送的出站事件,会直接通过管道管理的 ChannelOutboundHandler 列表从尾到头的触发,采用拦截器模式,由 ChannelOutboundHandler 决定是否继续调用下一个 ChannelOutboundHandler 处理。

1.3 小结

你会发现 ChannelPipeline 的主要功能就两个:

  1. 储存多个 ChannelHandler 的实例,将它们分为两类,入站事件处理器列表和出站事件处理器列表。
    • 其实 ChannelPipeline 里面储存的是由 ChannelHandler 创建的 ChannelHandlerContext 实例。
    • 储存的 ChannelHandler 列表是有顺序的,按照添加操作的顺序。
  2. IO 事件使用拦截器的模式通过 ChannelHandler 列表。
    • 对于入站事件是从头到尾地经过 ChannelInboundHandler 列表,由 ChannelInboundHandler 决定是否调用列表中下一个 ChannelInboundHandler
    • 对于出站事件是从尾到头地经过 ChannelOutboundHandler 列表,由 ChannelOutboundHandler 决定是否调用列表中上一个 ChannelOutboundHandler

二. ChannelHandlerContext 接口

2.1 介绍

上下文ChannelHandlerContext接口与 ChannelPipeline 联系非常大

其实它唯一创建的地方,就是当一个 ChannelHandler 添加到管道ChannelPipeline时,由ChannelPipeline创建一个包裹 ChannelHandler 的上下文ChannelHandlerContext对象添加进去。

ChannelHandlerContext 接口的重要作用:

  1. ChannelHandlerContext 包裹这一个 ChannelHandler, ChannelHandlerContext 必属于一个管道 ChannelPipeline
    • 这些都是在 ChannelHandlerContext 创建的时候就绑定的。
    • 因为ChannelHandlerContext获取到对应的管道,因此动态修改它所属的ChannelPipeline
  2. ChannelHandlerContext 继承 ChannelInboundInvokerChannelOutboundInvoker
    • 表示ChannelHandlerContext 也可以发送 IO 事件,它可以通知所属的ChannelPipeline 最接近的处理程序器处理 IO 事件。
    • 对于入站事件,最接近的处理程序器就是当前 ChannelHandler 在管道中下一个入站处理器ChannelInboundHandler
    • 对于出站事件,最接近的处理程序器就是当前 ChannelHandler 在管道中上一个出站处理器ChannelOutboundHandler
    • 其实 ChannelPipeline 的拦截器功能,就是通过ChannelHandlerContext实现的,因为由ChannelHandlerContext决定是否要调用列表中的下一个处理器处理。
  3. 继承 AttributeMap 接口

    attr(AttributeKey) 方法允许您存储和访问与ChannelHandler,Channel及其上下文相关的有效信息。

2.2 源码

public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {

    /**
     * 返回绑定到ChannelHandlerContext的通道Channel。
     */
    Channel channel();

    /**
     * 返回用于执行该上下文 ChannelHandlerContext 方法的执行器 EventExecutor,
     * 这个执行器 EventExecutor 可能和 通道Channel的EventExecutor一样,也有可能不一样。
     * 如果不一样,说明该上下文中方法的处理在另一个线程,不在通道Channel 的IO线程中处理,不会阻塞通道的IO线程。
     */
    EventExecutor executor();

    /**
     * ChannelHandlerContext的唯一名称。
     * 当将ChannelHandler添加到ChannelPipeline时使用该名称。
     * 可以使用此名称从ChannelPipeline 获取已注册的ChannelHandler。
     */
    String name();

    /**
     * 绑定此上下文的ChannelHandler对象。
     */
    ChannelHandler handler();

    /**
     * 如果属于此上下文的ChannelHandler已从ChannelPipeline中删除,则返回true。
     *
     * 注意这个方法只被EventLoop中的内部调用。
     */
    boolean isRemoved();

    @Override
    ChannelHandlerContext fireChannelRegistered();

    @Override
    ChannelHandlerContext fireChannelUnregistered();

    @Override
    ChannelHandlerContext fireChannelActive();

    @Override
    ChannelHandlerContext fireChannelInactive();

    @Override
    ChannelHandlerContext fireExceptionCaught(Throwable cause);

    @Override
    ChannelHandlerContext fireUserEventTriggered(Object evt);

    @Override
    ChannelHandlerContext fireChannelRead(Object msg);

    @Override
    ChannelHandlerContext fireChannelReadComplete();

    @Override
    ChannelHandlerContext fireChannelWritabilityChanged();

    @Override
    ChannelHandlerContext read();

    @Override
    ChannelHandlerContext flush();

    /**
     * 此上下文所属的管道`ChannelPipeline`。
     */
    ChannelPipeline pipeline();

    /**
     * Return the assigned {@link ByteBufAllocator} which will be used to allocate {@link ByteBuf}s.
     */
    ByteBufAllocator alloc();

    /**
     * @deprecated Use {@link Channel#attr(AttributeKey)}
     */
    @Deprecated
    @Override
     Attribute attr(AttributeKey key);

    /**
     * @deprecated Use {@link Channel#hasAttr(AttributeKey)}
     */
    @Deprecated
    @Override
     boolean hasAttr(AttributeKey key);
}

ChannelHandlerContext 的功能大概分为两类:

  1. 继承自 ChannelInboundInvokerChannelOutboundInvoker

    ChannelInboundInvokerChannelOutboundInvoker 将在下一篇文章中介绍。

  2. 获取属性
    • ChannelHandler handler(): 绑定此上下文的事件处理器ChannelHandler
    • ChannelPipeline pipeline(): 此上下文所属的管道ChannelPipeline
    • EventExecutor executor(): 此上下文对应的事件处理器ChannelHandler 方法运行所在的线程,有可能是所属通道Channel 的事件轮询器,也有可能是用户额外的事件执行器。
    • String name(): 该上下文的名字,在所属管道中是唯一的。
    • boolean isRemoved(): 此上下文从管道中移除时,返回true
    • Channel channel(),ByteBufAllocator alloc(),attr(AttributeKey key)hasAttr(AttributeKey key);都是从管道得到对应的通道Channel,然后从通道中再获取相关属性。

三. 总结

  1. ChannelPipeline 添加ChannelHandler时,会创建这个ChannelHandler 的上下文对象 ChannelHandlerContext,再添加到管道中。
  2. ChannelHandler 中可以得到这个上下文对象ChannelHandlerContext,这样它就可以:
    • 可以向上游或下游传递事件,实现责任链的功能,将事件传递给下一个处理器ChannelHandler 处理。
    • 可以动态修改管道ChannelPipeline,因为上下文对象可以获取所属的管道。因此它也可以从管道头或者尾重新处理事件。
    • 可以通过 attr(AttributeKey key) 存储特定于该处理器ChannelHandler的信息。

你可能感兴趣的:(Netty源码_ChannelPipeline和ChannelHandlerContext详解)