精進篇:netty源碼死磕6 html
巧奪天工——Pipeline模式揭祕設計模式
管道的發名者叫,Malcolm Douglas McIlroy,他也是Unix的建立者,是Unix文化的締造者之一。架構
40年前,Unix操做系統橫空出世,Unix不只僅帶來了一個操做系統,還創造C語言,Socket,開源,黑客等等文化,這些文化影響着整個計算機世界的文明,直到今天。app
若是說Unix是計算機文明中最偉大的發明,那麼,Unix下的Pipe管道就是跟隨Unix所帶來的另外一個偉大的發明。管道的出現,解決的就是讓不一樣功能的程序能夠互相連統統訊,從而可讓軟件開發,程序開發更加的「高內聚,低耦合」,從而可讓程序「Do one thing, Do it well」,從而可讓程序「Keep it Simple Stupid」等等,這一哲學引影了一代又一代的軟件架構,直到今天的雲計算。ide
管道模型,是一種「鏈式模型」,用來串接不一樣的程序或者不一樣的組件,讓它們組成一條直線的工做流。這樣給定一個完整的輸入,通過各個組件的前後協同處理,獲得惟一的最終輸出。編碼
簡單的說,管道模型的典型應用場景,能夠用一個形象的比方,有點相似像富士康那麼的工廠生產線。雲計算
管道模型包含兩個部分:pipeline 管道、valve 閥門。操作系統
pipeline 管道,能夠比做車間生產線,在這裏可認爲是容器的邏輯處理總線。設計
valve 閥門,能夠比做生產線上的工人,負責完成各自的部分工做。 閥門也能夠叫作Handler 處理者。netty
在咱們很是熟悉的Web容器Tomcat中,一個請求,首先被Connector接受到。而後,會將請求交給Container,Container處理完了以後將結果返回給Connector 。
Tomcat中,Container包含了Engine、Host、Context、Wrapper幾個內部的子容器元素。
這幾個子容器元素的功能,贅述以下:
Engine:表明一個完整的 Servlet 引擎,能夠包含多個Host。它接收來自Connector的請求,並決定傳給哪一個Host來處理,獲得Host處理完的結果後,返回給Connector。
Host:表明一個虛擬主機,一個Host能運行多個應用,它負責安裝和展開這些應用,每一個Host對應的一個域名。
Context:一個Context表明一個運行在Host上的Web應用
Wrapper: 一個Wrapper 表明一個 Servlet,它負責管理一個 Servlet,包括的 Servlet 的裝載、初始化、執行以及資源回收。
在一個用戶請求過來後,Tomcat中的每一級子容器,都對應於一個閥門Valve(注意:這個單詞不是value,有一個字母的差異)。Tomcat接受請求以後,請求從被接受,被分發,被處理,到最後轉變成http響應,會經過以下的閥門序列。
這些閥門(Valve)經過invoke(next)方法彼此串聯起來,最終構成的執行順序,構成一個管道。
Pipeline模式,在設計模式中,屬於責任鏈模式的一種。在Tomcat的Pipeline模式中。從Engine到Host再到Context一直到Wrapper,都是經過同一個責任鏈,來傳遞請求。
看完前面的《Netty 源碼(ChannelHandler 死磕)》一文,你們對Netty的Pipeline已經有初步的瞭解。
這裏再簡單的回顧一下。
一個Channel,擁有一個ChannelPipeline,做爲ChannelHandler的容器。
可是一個ChannelHandler,不能直接放進Pipeline中,必須包裹一個AbstractChannelHandlerContext 的上下文環境。
在初始化Netty的Channel時,須要將Handler加載到Pipeline中。
假定加載三個Handler,分別負責解碼、業務、編碼。三個Handler加載到ChannelPipeline的參考代碼以下:
@Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new DecoderHandler()); p.addLast(new BusinessHandler()); p.addLast(new EncoderHandler()); }
Netty中Channel加完Hander以後,Pipeline的容器內容圖以下:
Pipeline中不直接加入Handler,而是須要進行包裹。對應於Decoder、Business、Encoder三個Hander,分別建立三個默認的上下文包裹器(DefaultContext )。DefaultContext 的具體實現類,在Netty中,是DefaultChannelHandlerContext。
除此以外,Pipeline的頭尾,各有一個特別的上下文Context 。這兩個Hander Context ,不是默認的DefaultContext 。分別有本身的類型。
在Pipeline中頭尾,分別各有一個特別的HandlerContext——簡稱Head和Tail。Head的類型是HeadContext。Tail的類型是TailContext。這兩種類型,和DefaultChannelHandlerContext類型,都是AbstractChannelHandlerContext的子類。
Head和做用是什麼呢?
Head上下文包裹器的主要做用: 主要是做爲入站處理的起點。數據從Channel讀入以後,一個入站數據包從Channel的事件發送出來,首先從Head開始,被後面的全部的入站處理器,逐個進行入站處理。
大體的入站流程以下圖:
注意,TailContext,其實也是一個入站處理器。先按下不表,待會詳細闡述。
Tail的做用是什麼呢?
Tail上下文包裹器的主要做用: 主要是做爲出站處理的起點。當全部的入站處理器,都處理完成後,開始出站流程。須要出站的數據包,首先從Tail開始,被全部的出站處理器上下文Context中的Hander逐個進行處理。而後將處理結果,寫入Channel中。
注意,HeadContext,其實也是一個出站處理器。先按下不表,待會詳細闡述。
Tail和Head內部,沒有包裹其餘的內部Handler成員。這一點,是與默認的上下文包裹器DefaultChannelHandlerContext不一樣的地方。
TailContext自己實現了ChannelInboundHandler 接口的方式,能夠完成入站處理的操做,做爲一個入站處理器使用。
HeadContext自己,實現了ChannelOutboundHandler 接口的方式,能夠完成出站處理的操做,完成最終的出站處理操做。
總結一下Pipeline模式的優勢,以下:
一、下降耦合度。它將請求的發送者和接收者解耦。
二、簡化了Handler處理器。使得處理器不須要不須要知道鏈的結構。也就是Handler處理器能夠是無狀態的。與責任鏈(流水線)相關的狀態,交給了Context去維護。
三、加強給對象指派職責的靈活性。經過改變鏈內的成員或者調動它們的次序,容許動態地新增或者刪除責任。
四、 增長新的請求處理器很方便。
本節從宏觀上,解讀了什麼是Netty的pipeline。
下一篇:Pipeline的入站流程和出站流程