於每個Java工程師而言,tomcat這隻小橘貓算是咱們的老朋友了,同時tomcat做爲一款服務器中間件具有了很強的擴展性,內部對於Request和Response的邏輯處理都是何種方式來實現的呢?本文將主要介紹tomcat的Pipeline-Valve設計來一窺究竟。java
首先咱們看看Valve接口設計模式
能夠從Valve看到不少鏈表的影子,咱們能夠根據Valve來構造一條Valve鏈。接下來看看Pipeline接口tomcat
Pipeline接口的主要方法服務器
能夠看到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接口的實現類,包含了負載均衡、單點登陸等tomcat容器自己的邏輯。經過查看Valve接口invoke方法的實現能夠知道,每個Valve的invoke方法主要作兩件事情ide
這是很經典的責任鏈設計模式。簡單的說一個valve就是一個邏輯體。this
能夠看到setBasic的使用方主要是tomcat內置的四大容器,Context、Engine、Host以及Wrapper,先簡單對四大容器作個介紹spa
下面是關於四大容器一個簡單的類圖關係
那麼四大容器是如何被關聯在一塊兒的呢?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不只要執行自身相應的邏輯,同時也扮演了一個外交官的角色負責去和其子容器邏輯的對接。