08-ChannelPipeline接口

ChannelPipeline

  • ChannelPipeline用于组织全部的ChannelHandler,是ChannelHandler的容器。ChannelPipeline将一个ChannelHandler的处理后的数据作为下一个ChannelHandler处理的数据源。Netty的ChannelPipeline中的ChannelHandler示意图可以参考1.3中Netty源码中的表示;

  • Netty中是事件驱动,ChannelPipeline中流动的是事件(入站出站事件),事件中可能会附加数据。事件在ChannelPipeline中不自动流动而需要调用ChannelHandlerContext中诸如fireXXX()或者read()类似的方法将事件从一个ChannelHandler传播到下一个ChannelHandler。

  • 关于ChannelPipeline,在Netty源码中有比较大篇幅的介绍,其中有很多信息,在后面的源码中有注释,这里给出一些小结:

1.ChannelPipeline是一个ChannelHandler的集合,用于处理一个Channel的出站入站事件,ChannelPipeline采用了过滤器模式,这给用户提供
  了足够的处理事件的控制,用户可以方便的控制ChannelHandler之间的相互作用,每个Channel都有自己的ChannelPipeline
2.入站处理器处理入站事件,入站数据通常是IO线程产生的,通常是从通道远程读取到的
3.出站处理器处理出站事件,出站处理器通常产生或者转移出站事件,比如写响应消息,出站处理器处理完之后会给和Channel关联的IO线程处理,
  IO线程充当真实的发送角色,比如write
4.入站的时候通过fireXX的方法来将事件传递给下一个处理器
5.出站的时候,事件传播方法有:bind、connect、write、flush、read、disconnect、close、deregister等
6. pipeline中通常包含多个ChannelHandler来接受IO事件和处理IO操作,比如write和close一个典型的服务器将有下面这些ChannelHandler处理器,
   比如:Decoder、Encoder、Business Logic Handler
7.ChannelHandler是线程安全的,可以在任何时候添加或者删除,比如可以在即将交换敏感信息时插入加密处理程序,并在交换后将其删除。
8.下面是处理示例:
  p.addLast("1", new InboundHandlerA());
  p.addLast("2", new InboundHandlerB());
  p.addLast("3", new OutboundHandlerA());
  p.addLast("4", new OutboundHandlerB());
  p.addLast("5", new InboundOutboundHandlerX());
  按照上面的例子,5个处理器,入站的顺序是12345,出站的时候是54321,入站的时候只有125会处理,出站的时候543会处理

一、ChannelPipeline

  • ChannelPipeline接口定义了很多ChannelHandler的操作方法,比如添加ChannelHandler或者移除ChannelHandler,此外它继承了ChannelInboundInvoker和ChannelOutboundInvoker接口,我们先看看继承的接口;

1.1 ChannelInboundInvoker

  • ChannelInboundInvoker定义了ChannelInboundHandler之间的回调事件的回调方法,由用户进行具体实现。
/**
 * ChannelInboundInvoker定义了ChannelInboundHandler之间的回调事件的回调方法,由用户进行具体实现。
 */
public interface ChannelInboundInvoker {

    /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler的channelRegistered方法被调用
     * <p>
     * A {@link Channel} was registered to its {@link EventLoop}.
     * This will result in having the  {@link ChannelInboundHandler#channelRegistered(ChannelHandlerContext)} method
     * called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelInboundInvoker fireChannelRegistered();

    /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler的channelUnregistered方法被调用
     * <p>
     * A {@link Channel} was unregistered from its {@link EventLoop}.
     * This will result in having the  {@link ChannelInboundHandler#channelUnregistered(ChannelHandlerContext)} method
     * called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelInboundInvoker fireChannelUnregistered();

    /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler的channelActive方法被调用
     * A {@link Channel} is active now, which means it is connected.
     * <p>
     * This will result in having the  {@link ChannelInboundHandler#channelActive(ChannelHandlerContext)} method
     * called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelInboundInvoker fireChannelActive();

    /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler的channelInactive方法被调用
     * A {@link Channel} is inactive now, which means it is closed.
     * <p>
     * This will result in having the  {@link ChannelInboundHandler#channelInactive(ChannelHandlerContext)} method
     * called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelInboundInvoker fireChannelInactive();

    /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler的exceptionCaught方法被调用
     * A {@link Channel} received an {@link Throwable} in one of its inbound operations.
     * <p>
     * This will result in having the  {@link ChannelInboundHandler#exceptionCaught(ChannelHandlerContext, Throwable)}
     * method  called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelInboundInvoker fireExceptionCaught(Throwable cause);

    /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler的userEventTriggered方法被调用
     * A {@link Channel} received an user defined event.
     * <p>
     * This will result in having the  {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)}
     * method  called of the next  {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelInboundInvoker fireUserEventTriggered(Object event);

    /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler的channelRead方法被调用
     * A {@link Channel} received a message.
     * <p>
     * This will result in having the {@link ChannelInboundHandler#channelRead(ChannelHandlerContext, Object)}
     * method  called of the next {@link ChannelInboundHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    ChannelInboundInvoker fireChannelRead(Object msg);

    /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler一个channelReadComplete事件
     * <p>
     * Triggers an {@link ChannelInboundHandler#channelReadComplete(ChannelHandlerContext)}
     * event to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     */
    ChannelInboundInvoker fireChannelReadComplete();

    /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler一个channelWritabilityChanged事件
     * <p>
     * Triggers an {@link ChannelInboundHandler#channelWritabilityChanged(ChannelHandlerContext)}
     * event to the next {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     */
    ChannelInboundInvoker fireChannelWritabilityChanged();
}
  • 可以看到ChannelInboundInvoker中定义的方法基本上是用于在 ChannelHandler之前传播事件的方法,以fireXX为主,交给用户自行实现。

1.2 ChannelOutboundInvoker

  • ChannelOutboundInvoker定义了方法进行Channel内部IO操作(Channel发起bind/connect/close操作,Channel监听OP_READ,Channel写IO数据…),供用户在回调方法中使用。
  • 这里补充一点,ChannelPipeline和Channel都继承了ChannelOutboundInvoker接口,因此二者都具备这些方法,而在Channel的骨架子类AbstractChannel中,对这些方法的实现就是调用内部的ChannelPipeline的实现,这个在之前 Channel实现之AbstractChannel 中有提到。
  • 下面是ChannelOutboundInvoker接口主要方法,部分重载方法以及省略;
/**
 * ChannelOutboundInvoker定义了方法进行Channel内部IO操作(Channel发起bind/connect/close操作,Channel监听OP_READ,Channel写IO数据...),
 * 供用户在回调方法中使用。ChannelPipeline和Channel都继承了ChannelOutboundInvoker接口,因此二者都具备这些方法,而在Channel的骨架子
 * 类AbstractChannel中,对这些方法的实现就是调用内部的ChannelPipeline的实现
 */
public interface ChannelOutboundInvoker {

    /**
     * Request to bind to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation
     * completes, either because the operation was successful or because of an error.
     * 绑定到指定地址,完成后会通知ChannelFuture,不管成功或者失败
     */
    ChannelFuture bind(SocketAddress localAddress);

    /**
     * 连接到指定地址,操作完成后通知ChannelFuture,不管成功或者失败
     * Request to connect to the given {@link SocketAddress} and notify the {@link ChannelFuture} once the operation
     * completes, either because the operation was successful or because of an error.
     */
    ChannelFuture connect(SocketAddress remoteAddress);

    /**
     * 请求断开连接,操作完成后通知ChannelFuture,不管成功或者失败
     * Request to disconnect from the remote peer and notify the {@link ChannelFuture} once the operation completes,
     * either because the operation was successful or because of an error.
     */
    ChannelFuture disconnect();

    /**
     * 关闭Channel,完成后通知ChannelFuture,不管成功或者失败
     * Request to close the {@link Channel} and notify the {@link ChannelFuture} once the operation completes,
     * either because the operation was successful or because of an error.
     */
    ChannelFuture close();

    /**
     * 将Channel从EventExecutor注销,完成后会通知ChannelFuture,,不管成功或者失败
     * Request to deregister from the previous assigned {@link EventExecutor} and notify the
     * {@link ChannelFuture} once the operation completes, either because the operation was successful or because of
     * an error.
     */
    ChannelFuture deregister();

    /**
     * 断开和远程地址之间的连接,并且操作完成后通知ChannelFuture,不管成功或者失败
     * Request to disconnect from the remote peer and notify the {@link ChannelFuture} once the operation completes,
     * either because the operation was successful or because of an error.
     */
    ChannelFuture disconnect(ChannelPromise promise);

    /**
     * 从Channel读数据到入站buffer,如果读到数据就触发一次channelRead事件,如果可以继续读取数据会触发channelReadComplete事件
     * Request to Read data from the {@link Channel} into the first inbound buffer, triggers an
     * {@link ChannelInboundHandler#channelRead(ChannelHandlerContext, Object)} event if data was
     * read, and triggers a
     * {@link ChannelInboundHandler#channelReadComplete(ChannelHandlerContext) channelReadComplete} event so the
     * handler can decide to continue reading.  If there's a pending read operation already, this method does nothing.
     */
    ChannelOutboundInvoker read();

    /**
     * 请求通过ChannelPipeline写数据 不会触发flush
     * Request to write a message via this {@link ChannelHandlerContext} through the {@link ChannelPipeline}.
     * This method will not request to actual flush, so be sure to call {@link #flush()}
     * once you want to request to flush all pending data to the actual transport.
     */
    ChannelFuture write(Object msg);

    /**
     * flush所有消息
     * Request to flush all pending messages via this ChannelOutboundInvoker.
     */
    ChannelOutboundInvoker flush();

    /**
     * 写消息,并且flush
     * Shortcut for call {@link #write(Object, ChannelPromise)} and {@link #flush()}.
     */
    ChannelFuture writeAndFlush(Object msg, ChannelPromise promise);

    /**
     * 返回一个新的ChannelPromise
     */
    ChannelPromise newPromise();

    /**
     * 返回一个新的ChannelProgressivePromise
     */
    ChannelProgressivePromise newProgressivePromise();

    /**
     * 返回成功的ChannelFuture
     * Create a new {@link ChannelFuture} which is marked as succeeded already. So {@link ChannelFuture#isSuccess()}
     * will return {@code true}. All {@link FutureListener} added to it will be notified directly. Also
     * every call of blocking methods will just return without blocking.
     */
    ChannelFuture newSucceededFuture();

    /**
     * 返回失败的ChannelFuture
     * Create a new {@link ChannelFuture} which is marked as failed already. So {@link ChannelFuture#isSuccess()}
     * will return {@code false}. All {@link FutureListener} added to it will be notified directly. Also
     * every call of blocking methods will just return without blocking.
     */
    ChannelFuture newFailedFuture(Throwable cause);

    /**
     * Return a special ChannelPromise which can be reused for different operations.
     */
    ChannelPromise voidPromise();
}
  • ChannelOutboundInvoker中定义的方法主要是IO方法,比如bind、read、write、register和close之类的

1.3 ChannelPipeline接口

/**
 * ChannelPipeline是一个ChannelHandler的集合,用于处理一个Channel的出站入站事件
 * ChannelPipeline采用了过滤器模式,这给用户提供了足够的处理事件的控制,用户可以方便的控制ChannelHandler之间的相互作用
 * 每个Channel都有自己的ChannelPipeline
 * A list of {@link ChannelHandler}s which handles or intercepts inbound events and outbound operations of a
 * {@link Channel}.  {@link ChannelPipeline} implements an advanced form of the
 * <a href="http://www.oracle.com/technetwork/java/interceptingfilter-142169.html">Intercepting Filter</a> pattern
 * to give a user full control over how an event is handled and how the {@link ChannelHandler}s in a pipeline
 * interact with each other.
 *
 * <h3>Creation of a pipeline</h3>
 *
 * Each channel has its own pipeline and it is created automatically when a new channel is created.
 *
 * <h3>How an event flows in a pipeline</h3>
 *
 * 下图展示了一个ChannelPipeline中的ChannelHandler是如何处理IO事件,一个事件可以被入站或者出站处理器处理,事件可以再相邻的ChannelHandler
 * 之间传播,通过调用ChannelHandlerContext的方法来传播,比如fireChannelRead或者write
 * The following diagram describes how I/O events are processed by {@link ChannelHandler}s in a {@link ChannelPipeline}
 * typically. An I/O event is handled by either a {@link ChannelInboundHandler} or a {@link ChannelOutboundHandler}
 * and be forwarded to its closest handler by calling the event propagation methods defined in
 * {@link ChannelHandlerContext}, such as {@link ChannelHandlerContext#fireChannelRead(Object)} and
 * {@link ChannelHandlerContext#write(Object)}.
 *
 * <pre>
 *                                                 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)            |
 *  +-------------------------------------------------------------------+
 * </pre>
 *  入站处理器处理入站事件,入站数据通常是IO线程产生的,通常是从通道远程读取到的,比如使用read,入站处理器处理完毕之后会默默丢弃
 * An inbound event is handled by the inbound handlers in the bottom-up direction as shown on the left side of the
 * diagram.  An inbound handler usually handles the inbound data generated by the I/O thread on the bottom of the
 * diagram.  The inbound data is often read from a remote peer via the actual input operation such as
 * {@link SocketChannel#read(ByteBuffer)}.  If an inbound event goes beyond the top inbound handler, it is discarded
 * silently, or logged if it needs your attention.
 * <p>
 * 出站处理器处理出站事件,出站处理器通常产生或者转移出站事件,比如写响应消息,出站处理器处理完之后会给和Channel关联的IO线程处理,
 * IO线程充当真实的发送角色,比如write
 * An outbound event is handled by the outbound handler in the top-down direction as shown on the right side of the
 * diagram.  An outbound handler usually generates or transforms the outbound traffic such as write requests.
 * If an outbound event goes beyond the bottom outbound handler, it is handled by an I/O thread associated with the
 * {@link Channel}. The I/O thread often performs the actual output operation such as
 * {@link SocketChannel#write(ByteBuffer)}.
 * <p>
 * For example, let us assume that we created the following pipeline:
 * <pre>
 * {@link ChannelPipeline} p = ...;
 * p.addLast("1", new InboundHandlerA());
 * p.addLast("2", new InboundHandlerB());
 * p.addLast("3", new OutboundHandlerA());
 * p.addLast("4", new OutboundHandlerB());
 * p.addLast("5", new InboundOutboundHandlerX());
 * </pre>
 * In the example above, the class whose name starts with {@code Inbound} means it is an inbound handler.
 * The class whose name starts with {@code Outbound} means it is a outbound handler.
 * <p>
 * 按照上面的例子,5个处理器,入站的顺序是12345,出站的时候是54321,入站的时候只有125会处理,出站的时候543会处理
 * In the given example configuration, the handler evaluation order is 1, 2, 3, 4, 5 when an event goes inbound.
 * When an event goes outbound, the order is 5, 4, 3, 2, 1.  On top of this principle, {@link ChannelPipeline} skips
 * the evaluation of certain handlers to shorten the stack depth:
 * <ul>
 * <li>3 and 4 don't implement {@link ChannelInboundHandler}, and therefore the actual evaluation order of an inbound
 *     event will be: 1, 2, and 5.</li>
 * <li>1 and 2 don't implement {@link ChannelOutboundHandler}, and therefore the actual evaluation order of a
 *     outbound event will be: 5, 4, and 3.</li>
 * <li>If 5 implements both {@link ChannelInboundHandler} and {@link ChannelOutboundHandler}, the evaluation order of
 *     an inbound and a outbound event could be 125 and 543 respectively.</li>
 * </ul>
 *
 * <h3>Forwarding an event to the next handler</h3>
 * 入站的时候通过fireXX的方法来将事件传递给下一个处理器
 * As you might noticed in the diagram shows, a handler has to invoke the event propagation methods in
 * {@link ChannelHandlerContext} to forward an event to its next handler.  Those methods include:
 * <ul>
 * <li>Inbound event propagation methods:
 *     <ul>
 *     <li>{@link ChannelHandlerContext#fireChannelRegistered()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelActive()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelRead(Object)}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelReadComplete()}</li>
 *     <li>{@link ChannelHandlerContext#fireExceptionCaught(Throwable)}</li>
 *     <li>{@link ChannelHandlerContext#fireUserEventTriggered(Object)}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelWritabilityChanged()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelInactive()}</li>
 *     <li>{@link ChannelHandlerContext#fireChannelUnregistered()}</li>
 *     </ul>
 * </li>
 * 出站的时候,事件传播方法有:bind、connect、write、flush、read、disconnect、close、deregister等
 * <li>Outbound event propagation methods:
 *     <ul>
 *     <li>{@link ChannelHandlerContext#bind(SocketAddress, ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#write(Object, ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#flush()}</li>
 *     <li>{@link ChannelHandlerContext#read()}</li>
 *     <li>{@link ChannelHandlerContext#disconnect(ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#close(ChannelPromise)}</li>
 *     <li>{@link ChannelHandlerContext#deregister(ChannelPromise)}</li>
 *     </ul>
 * </li>
 * </ul>
 *
 * 下面演示了一般情况下事件是如何传播的:
 * and the following example shows how the event propagation is usually done:
 *
 * 入站:
 * <pre>
 * public class MyInboundHandler extends {@link ChannelInboundHandlerAdapter} {
 *     {@code @Override}
 *     public void channelActive({@link ChannelHandlerContext} ctx) {
 *         System.out.println("Connected!");
 *         ctx.fireChannelActive();
 *     }
 * }
 *
 * 出站:
 * public class MyOutboundHandler extends {@link ChannelOutboundHandlerAdapter} {
 *     {@code @Override}
 *     public void close({@link ChannelHandlerContext} ctx, {@link ChannelPromise} promise) {
 *         System.out.println("Closing ..");
 *         ctx.close(promise);
 *     }
 * }
 * </pre>
 *
 * 创建一个pipeline,我们应该在pipeline中包含多个ChannelHandler来接受IO事件和处理IO操作,比如write和close
 * 一个典型的服务器将有下面这些ChannelHandler处理器,比如:Decoder、Encoder、Business Logic Handler,
 * 但是可能会因为你的协议和业务逻辑复杂性而不同
 *
 * <h3>Building a pipeline</h3>
 * <p>
 * A user is supposed to have one or more {@link ChannelHandler}s in a pipeline to receive I/O events (e.g. read) and
 * to request I/O operations (e.g. write and close).  For example, a typical server will have the following handlers
 * in each channel's pipeline, but your mileage may vary depending on the complexity and characteristics of the
 * protocol and business logic:
 *
 * <ol>
 * <li>Protocol Decoder - translates binary data (e.g. {@link ByteBuf}) into a Java object.</li>
 * <li>Protocol Encoder - translates a Java object into binary data.</li>
 * <li>Business Logic Handler - performs the actual business logic (e.g. database access).</li>
 * </ol>
 *
 * and it could be represented as shown in the following example:
 * 下面是一个例子:
 * <pre>
 * static final {@link EventExecutorGroup} group = new {@link DefaultEventExecutorGroup}(16);
 * ...
 *
 * {@link ChannelPipeline} pipeline = ch.pipeline();
 *
 * pipeline.addLast("decoder", new MyProtocolDecoder());
 * pipeline.addLast("encoder", new MyProtocolEncoder());
 *
 * // Tell the pipeline to run MyBusinessLogicHandler's event handler methods
 * // in a different thread than an I/O thread so that the I/O thread is not blocked by
 * // a time-consuming task.
 * // If your business logic is fully asynchronous or finished very quickly, you don't
 * // need to specify a group.
 * pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
 * </pre>
 *
 * ChannelHandler是线程安全的,可以在任何时候添加或者删除,比如可以在即将交换敏感信息时插入加密处理程序,并在交换后将其删除。
 * <h3>Thread safety</h3>
 * <p>
 * A {@link ChannelHandler} can be added or removed at any time because a {@link ChannelPipeline} is thread safe.
 * For example, you can insert an encryption handler when sensitive information is about to be exchanged, and remove it
 * after the exchange.
 */
public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable<Entry<String, ChannelHandler>> {

    /**
     * 在开始的位置添加一个ChannelHandler
     */
    ChannelPipeline addFirst(String name, ChannelHandler handler);

    /**
     * 在末尾位置添加一个ChannelHandler
     */
    ChannelPipeline addLast(String name, ChannelHandler handler);

    /**
     * 在指定ChannelHandler前面添加一个ChannelHandler
     */
    ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);

    /**
     * 在指定ChannelHandler后面添加一个ChannelHandler
     */
    ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);

    /**
     * 移除ChannelHandler
     */
    ChannelPipeline remove(ChannelHandler handler);

    /**
     * Returns the last {@link ChannelHandler} in this pipeline.
     * 返回最后一个ChannelHandler
     */
    ChannelHandler last();
 
    /**
     * 根据名字获取ChannelHandler
     */
    ChannelHandler get(String name);
    
    //省略其他代码...
}

二、事件

2.1 入站事件

  • 入站事件一般由IO线程触发,下面是可能的入站事件
    ChannelRegistered() // Channel注册到EventLoop
    ChannelActive()     // Channel激活
    ChannelRead(Object) // Channel读取到数据
    ChannelReadComplete()   // Channel读取数据完毕
    ExceptionCaught(Throwable)  // 捕获到异常
    UserEventTriggered(Object)  // 用户自定义事件
    ChannelWritabilityChanged() // Channnel可写性改变,由写高低水位控制
    ChannelInactive()   // Channel不再激活
    ChannelUnregistered()   // Channel从EventLoop中注销

2.2 出站事件

  • 出站事件一般由用户触发,以下事件为出站事件:
    bind(SocketAddress, ChannelPromise) // 绑定到本地地址
    connect(SocketAddress, SocketAddress, ChannelPromise)   // 连接一个远端机器
    write(Object, ChannelPromise)   // 写数据,实际只加到Netty出站缓冲区
    flush() // flush数据,实际执行底层写
    read()  // 读数据,实际设置关心OP_READ事件,当数据到来时触发ChannelRead入站事件
    disconnect(ChannelPromise)  // 断开连接,NIO Server和Client不支持,实际调用close
    close(ChannelPromise)   // 关闭Channel
    deregister(ChannelPromise)  // 从EventLoop注销Channel

三、Channel和ChannelPipeline

  • 在Channel的骨架实现类AbstractChannel中,我们看看它的构造方法
    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        //1.创建ChannelId对象,对应Channel编号
        id = newId();
        //2.创建Unsafe对象,使用在Channel的生命周期
        unsafe = newUnsafe();
        //3.创建ChannelPipeline对象,是子类DefaultChannelPipeline的实例
        pipeline = newChannelPipeline();
    }
    
        protected DefaultChannelPipeline newChannelPipeline() {
        return new DefaultChannelPipeline(this);
    }
  • 我们看到构造一个Channel对象的时候,就会初始化其内部的pipeline属性,创建对应的Pipeline对象,因此Channel和ChannelPipeline是一一对应的关系,Channel的很多方法内部就是委托ChannelPipeline完成的。

四、小结

  • ChannelPipeline是一个ChannelHandler的集合,它和Channel一一对应,内部存放了用于处理Channel的出入站事件的ChannelHandler;
  • ChannelPipeline继承了ChannelInboundInvoker和ChannelOutboundInvoker,二者分别定义了事件回调方法和IO操作方法,ChannelOutboundInvoker同时被Channel和ChannelPipeline继承,Channel中很多IO操作就是委托ChannelPipeline实现的;
  • ChannelPipeline内部的处理器分2种类型,事件在流动过程中只会被对应的处理器处理;
  • ChannelPipeline中的ChannelHandler之间的入站事件的传播注意是用户控制,通过fireXX方法控制,出站事件主要是一些IO操作,比如bind、connect、write、flush、read、disconnect、close、deregister等;
  • ChannelPipeline是线程安全的,这一点需要注意;
  • 下一篇文章我们具体看看ChannelPipeline的主要实现类DefaultChannelPipeline的实现细节;

五、参考

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值