吸貓就吸Tomcat之Pipeline-Valve巧妙設計

前言

於每個Java工程師而言,tomcat這隻小橘貓算是咱們的老朋友了,同時tomcat做爲一款服務器中間件具有了很強的擴展性,內部對於Request和Response的邏輯處理都是何種方式來實現的呢?本文將主要介紹tomcat的Pipeline-Valve設計來一窺究竟。java

接口介紹

首先咱們看看Valve接口設計模式

image-20190526123653021

能夠從Valve看到不少鏈表的影子,咱們能夠根據Valve來構造一條Valve鏈。接下來看看Pipeline接口tomcat

Pipeline接口的主要方法服務器

image-20190526120956032

能夠看到Pipeline的主要方法提供了對Valve的增刪查改操做,其中有兩個關鍵的方法setBasic(Valve)與addValve(Valve)咱們跟進源碼看一看。其中StandardPipeline是Pipeline接口的實現類,下面我截取了setBasic最核心的邏輯,能夠看出basic實際上就是Pipeline維護的Valve鏈裏最末尾的一個Valve架構

Valve current = first;
while (current != null) {
if (current.getNext() == oldBasic) {
current.setNext(valve);
break;
}
current = current.getNext();
}

this.basic = valve;
複製代碼

一樣的咱們來看一看addValve的源碼,如下是最核心的部分app

Valve current = first;
while (current != null) {
if (current.getNext() == basic) {
current.setNext(valve);
valve.setNext(basic);
break;
}
複製代碼

經過addValve添加的Valve被加在了basic的前一個,也就是說basic永遠指向Valve鏈裏的最後一個Valve,不會被輕易替代,那麼這種設計有什麼意義呢?待會給出答案~負載均衡

Valve究竟是什麼?

image-20190526133007212

上圖都是Valve接口的實現類,包含了負載均衡、單點登陸等tomcat容器自己的邏輯。經過查看Valve接口invoke方法的實現能夠知道,每個Valve的invoke方法主要作兩件事情ide

  1. 自己的邏輯
  2. 經過getNext().invoke(request, response)調用下一個Valve的邏輯

這是很經典的責任鏈設計模式。簡單的說一個valve就是一個邏輯體。this

跟蹤basic

image-20190526125355280

能夠看到setBasic的使用方主要是tomcat內置的四大容器,Context、Engine、Host以及Wrapper,先簡單對四大容器作個介紹spa

  • Wrapper:對Servlet定義的組件概念,一個Wrapper表明一個Servlet
  • Context:表示咱們的應用程序,好比一個運行中Java Web程序,一個程序裏面天然有多個Servlet,因此Conxtet和Wrapper的關係是1對n
  • Host:表示虛擬主機的概念,由於一臺服務器不只可以對product.yangkw.com提供服務,同時也能夠對test.yangkw.com提供服務,同時每一個虛擬主機均可以運行多個Java Web程序,因此Host和Context的關係也是1對n
  • Engine:Tomcat鏈接器(Connector) 將接收到的鏈接提交給Engine處理,做爲整個Servlet引擎的組件概念,用來管理多個虛擬站點,Engine和Host也是一對n的關係

下面是關於四大容器一個簡單的類圖關係

image-20190526131102483

那麼四大容器是如何被關聯在一塊兒的呢?StandardEngineValve是Engine容器的basic valve,筆者簡化了代碼實現,保留最主要的邏輯

@Override
public final void invoke(Request request, Response response) throws IOException, ServletException {

// Select the Host to be used for this Request
Host host = request.getHost();

...
// Ask this Host to process this request
host.getPipeline().getFirst().invoke(request, response);

}
複製代碼

能夠看到Engine容器的basic valve負責觸發host容器pipeline 答案出來了:每一個容器的basic valve會去觸發子容器的pipeline,因此basic做爲一個valve不只要執行自身相應的邏輯,同時也扮演了一個外交官的角色負責去和其子容器邏輯的對接。

總結

img

  • pipeline能夠看作是valve的容器
  • 四大容器裏每一個容器都維護有自身專屬的pipeline
  • basic負責觸發子容器的第一個valve
  • wrapper的basic會去調用filter,而後再執行servlet的邏輯
  • FilterChain和Pipeline-Valve很類似,區別是filterChain是業務層面裏的而Pipeline-Valve是tomcat自身層面的。

參考資料

  • 《Tomcat 架構解析》
  • 極客時間《深刻拆解Tomcat&Jetty》
相關文章
相關標籤/搜索