下面是ChannelPipeline的java doc文檔的部分介紹
/**
* 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
* 是一個處理或者在一個channel上的攔截入站事件和出站事件操作的ChannelHandler的集合
* <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.
* channelpipeline實現了一種高級的攔截過濾器模式,讓用戶完全自主控制一個事件是怎麼被處理的,以及在pipeline中channelHandler是怎麼跟彼此交互的
* <h3>Creation of a pipeline</h3>
* 創建一個pipeline
* Each channel has its own pipeline and it is created automatically when a new channel is created.
* 每個channel都會有自己的pipeline,它是在一個新的channel被創建的時候自動創建的
* <h3>How an event flows in a pipeline</h3>
* 一個事件是怎麼在一個pipeline中流動 的
* 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)}.
* 下面的類圖描繪了IO事件是怎樣被在channelpipeline中的channelhandler所處理的。
* 一個io事件被一個ChannelInboundHandler或者一個ChannelOutboundHandler所處理,
通過在ChannelHandlerContext中定義的事件傳播機制去調用離他們最近的handler,
* 例如ChannelHandlerContext#fireChannelRead(Object) 和 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>
* 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.
* 一個入站事件是被入站handlers所處理,在這個類圖的左邊顯示的那樣,以一個從下至上的方向進行,
一個入站handler通常處理通過在類圖底部的io線程生成的入站數據。
* 入站數據經常從一個遠程節點讀取,通過一個真是存在的輸入操作,如果一個入站事件從頂部的入站handler走出去了,
它就會被默默的丟棄掉,或者如果你需要關注他,你通過日誌的方式記錄下來。
* <p>
* 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)}.
* 如果一個出站的事件走出了底部的出站handler,他就會被與這個channel相關的io線程處理。
* <p>
*
* <h3>Forwarding an event to the next handler</h3>
* 傳播一個事件到下一個handler中
* 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>
一個handler必須調用ChannelHandlerContext中的時間傳播方法來將一個事件傳播到它的下一個handler中。比如ctx.fireChannelActive();
* </pre>
*
* <h3>Building a pipeline</h3>
*
* // 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());
* 告訴pipeline在一個與IO線程不同的線程中去運行MyBusinessLogicHandler's的事件處理方法,這樣IO線程就不會因爲一個耗時的任務而被阻塞
* 如果你的業務邏輯是完全異步的 ,或者執行速度很快,你可以不必指定一個group.
* </pre>
*
* <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.
* channelHandler可以在任何時候進行添加和移除,因爲ChannelPipeline是線程安全的。
* 例如,當敏感的信息要進行交換時,你可以插入一個加密的handler,當信息交換完畢之後,刪除掉這個handler.
*/
我們主要看Pipeline的默認實現DefaultChannelPipeline中的addLast方法的實現
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
//創建一個新的handler上下文
newCtx = newContext(group, filterName(name, handler), handler);
//將這個新創建的handler上下文添加到pipeline的末端,這裏面使用鏈表的操作方式。
addLast0(newCtx);
// If the registered is false it means that the channel was not registered on an eventloop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
//如果registered是fasle,這就意味着channel目前還沒有被註冊到eventloop中,
//在這種情況下,我們會將context添加到這個pipeline中,並且添加一個一旦channel被註冊了就會調用ChannelHandler.handlerAdded()的任務
//很明顯,一開始我們是沒有註冊的,所以爲false
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
newCtx.setAddPending();
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerAdded0(newCtx);
}
});
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
private void callHandlerCallbackLater(AbstractChannelHandlerContext ctx, boolean added) {
assert !registered;
//added爲true,實例化一個PendingHandlerAddedTask,這個類是一個Runnable接口的具體實現,是一個線程任務,
PendingHandlerCallback task = added ? new PendingHandlerAddedTask(ctx) : new PendingHandlerRemovedTask(ctx);
PendingHandlerCallback pending = pendingHandlerCallbackHead;
//pending爲空的時候,說明任務還沒有,那麼將這個任務賦予pendingHandlerCallbackHead,作爲頭一個任務
//如果有,則賦給頭一個任務的下一個(鏈表操作)
if (pending == null) {
pendingHandlerCallbackHead = task;
} else {
// Find the tail of the linked-list.
while (pending.next != null) {
pending = pending.next;
}
pending.next = task;
}
}
將handler添加到鏈表的最後的方法實現
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
最終的目的就是讓新創建的newCtx插入到tail之前,並且更新newCtx前後兩個ctx的next以及prev的值,以及本身的next和prev的值,實現鏈表的插入