Pipeline(netty原始碼)
精進篇:netty原始碼死磕6
巧奪天工——Pipeline模式揭祕
1. 巧奪天工——Pipeline模式揭祕
1.1. Pipeline模式簡介
管道的發名者叫,Malcolm Douglas McIlroy,他也是Unix的建立者,是Unix文化的締造者之一。
40年前,Unix作業系統橫空出世,Unix不僅僅帶來了一個作業系統,還創造C語言,Socket,開源,黑客等等文化,這些文化影響著整個計算機世界的文明,直到今天。
如果說Unix是計算機文明中最偉大的發明,那麼,Unix下的Pipe管道就是跟隨Unix所帶來的另一個偉大的發明。管道的出現,解決的就是讓不同功能的程式可以互相連通通訊,從而可以讓軟體開發,程式開發更加的“高內聚,低耦合”,從而可以讓程式“Do one thing, Do it well”,從而可以讓程式“Keep it Simple Stupid”等等,這一哲學引影了一代又一代的軟體架構,直到今天的雲端計算。
管道模型,是一種“鏈式模型”,用來串接不同的程式或者不同的元件,讓它們組成一條直線的工作流。這樣給定一個完整的輸入,經過各個元件的先後協同處理,得到唯一的最終輸出。
1.2. Pipeline模式應用場景
簡單的說,管道模型的典型應用場景,可以用一個形象的比方,有點類似像富士康那麼的工廠生產線。
管道模型包含兩個部分:pipeline 管道、valve 閥門。
pipeline 管道,可以比作車間生產線,在這裡可認為是容器的邏輯處理匯流排。
valve 閥門,可以比作生產線上的工人,負責完成各自的部分工作。 閥門也可以叫做Handler 處理者。
1.3. Tomcat中的Pipeline模式
在我們非常熟悉的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,都是通過同一個責任鏈,來傳遞請求。
1.4. Netty中的Pipeline模式
看完前面的《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 。分別有自己的型別。
1.5. Context的型別
在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 介面的方式,可以完成出站處理的操作,完成最終的出站處理操作。
1.6. Pipeline模式的優點:
總結一下Pipeline模式的優點,如下:
1、降低耦合度。它將請求的傳送者和接收者解耦。
2、簡化了Handler處理器。使得處理器不需要不需要知道鏈的結構。也就是Handler處理器可以是無狀態的。與責任鏈(流水線)相關的狀態,交給了Context去維護。
3、增強給物件指派職責的靈活性。通過改變鏈內的成員或者調動它們的次序,允許動態地新增或者刪除責任。
4、 增加新的請求處理器很方便。
1.7. 小結
本節從巨集觀上,解讀了什麼是Netty的pipeline。
下一篇:Pipeline的入站流程和出站流程