在前面的文章中,我們介紹了Tomcat的連接器Connector,連接器會監聽指定的埠,并把接受到的訊息轉為HttpServletRequest和HttpServletResponse,交個Servlet容器處理,Tomcat的Servlet容器分為四種:Engin容器/Host容器/Context容器/Wrapper容器,這四個容器之間是父子關系,Engine容器包含Host容器,Host容器包含Context,Context包含Wrapper容器,本文會介紹Tomcat容器中的Engin容器和Host容器,在下一篇文章中會介紹Context容器和Wrapper容器,
Container的作用
Tomcat中的Container用于處理連接器處理好的Request和Response,Tomcat中的四種容器都繼承自Container介面,其中Engin容器全域只有一個,是Container對外提供處理Request和Response的入口,Host容器是Engin容器的子容器,一個Engin容器可以包含多個Host容器,每個Host容器代表一個虛擬主機(下文會詳細介紹),Engin容器在收到請求之后,會按照虛擬主機的配置將請求映射到對應的Host容器之上,

Container的結構
如下圖所示,Tomcat中的四種Container都有相同的結構,包含以下幾部分關鍵組件:請求處理閥門鏈PipeLine、基礎閥門BaseValve和日志組件等,
- PipeLine:用于流式加工處理請求中的資訊,每個PipeLine中可以包含多個閥門Valve,每個Valve都有同樣的方法
invoke(Request request,Response response),
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- 默認 Valve -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
<!-- maxDays="5" -->
pattern="%h %l %u %t "%r" %s %b" />
<!-- 自定義 valve -->
<Valve className="org.apache.catalina.valves.WswAccessValve"/>
</Host>
</Engine>
- BaseValve:基礎閥門,和Piple中的閥門的介面相同方法:
invoke(Request request,Response response),但是作用和Piple中的閥門不同,主要用于將請求傳遞到下一個容器或者對應的Servlet組件, - 日志記錄器和生命周期管理等組其它組件,不具體介紹,

Engine容器

如上圖所示,每個Tomcat僅僅有一個Engin容器,Tomcat中的連接器接受并決議訊息之后,會把訊息的轉給Engin容器,用戶可以給Engin容器的PipeLine添加各種自定義的Valve,Engin容器會將一一呼叫PipeLine中的Valve,Engin容器的BaseValve是StandardEngineValve,這個Valve會讀取Request中的Host資訊,然后把請求路由給對應的Host容器,
final class StandardEngineValve extends ValveBase {
public StandardEngineValve() {
super(true);
}
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// Ignore some code here.
// Select the Host to be used for this Request
Host host = request.getHost();
// Ignore some code here.
// Ask this Host to process this request
host.getPipeline().getFirst().invoke(request, response);
}
}
Host容器
Host容器是Engine容器的子容器,每個Host容器都是一個虛擬主機,對應于不同的域名,http協議從1.1開始,支持在請求頭里面添加Host欄位用來表示請求的域名,DNS域名決議的時候,可以將不同的域名決議到同一個ip或者主機,Engine容器的BaseValve會讀取Request中的Host,然后呼叫對應Host容器的PipeLine去處理訊息,

什么是虛擬主機
假如我們需要在一個tomcat里面同時支持三個域名:
- http://www.ramki.com
- http://www.krishnan.com
- http://www.blog.ramki.com
我們需要在server.xml檔案里面的Engine標簽下面添加多個Host標簽,如下所示,其中name表示域名,appbase表示虛擬主機的目錄,當我們在瀏覽器輸入http://www.ramki.com之后,相應域名將請求到tomcat,tomcat通過讀取并搜索server.xml,找到www.ramki.com對應的虛擬主機Host,然后就使用查找到的Host來處理請求,
<Host name="www.ramki.com" appbase="ramki_webapps" />
<Host name="www.krishnan.com" appbase="krishnan_webapps" />
<Host name="www.blog.ramki.com" appbase="blog_webapps" />
在瀏覽器請求的時候,請求頭資訊如下,這兒我們重點關注Host header,
GET /appA/servletA/some-url HTTP/1.1
Host: www.ramki.com
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11
Accept: text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Context容器
Tomcat中一個Host容器可以包含多個Context容器,通常情況下一個Context容器標識一個應用,對應于wabapp目錄下面的一個工程,在我的下一篇博客中會詳細介紹Context容器,
我是御狐神,歡迎大家關注我的微信公眾號:wzm2zsd

本文最先發布至微信公眾號,著作權所有,禁止轉載!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/302345.html
標籤:Java
上一篇:Docker 鏡像優化:從 1.16 GB 到 22.4MB!怎么做到的??
下一篇:列舉與注解
