文章目录
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的实现细节;
五、参考
- [1] pipeline原理与事件处理