希望各位網友在看完<<how tomcat works>>一書或者鄙人的tomcat專欄文章後再看這篇部落格
這裡主要是梳理各個章節的核心概念
第一章 一個簡單的Web伺服器
第1章從這本書一開始就介紹了一個簡單的HTTP伺服器。要建立一個可工作的HTTP伺服器,你需要知道在 java.net 包裡邊的 2 個類的内部運作:Socket 和 ServerSocket。這裡有關于這 2個類足夠的背景資料,使得你能夠了解附帶程式是如何工作的。
類圖如下:
程式的main方法中,建立HttpServer,調用await方法,從ServerSocket中取得inputstream與outputstream分别傳遞給Request類與Response類,最後調用Response的sendStaticResource方法.靜态資源的處理方法就是,在預設的檔案路徑下按照分析出來的uri讀取對應的檔案,然後再調用outputstream的write方法。
第二章 一個簡單的servlet容器
第一章的程式,隻能處理靜态資源,這一章的程式就能處理簡單的servlet。
第 2 章說明簡單的 servlet 容器是如何工作的。這一章帶有 2 個 servlet 容器應用,可以處理靜态資源和簡單的 servlet 請求。尤其是你将會學到如何建立 request 和 response 對象,然後把它們傳遞給被請求的 servlet 的 service 方法。在 servlet 容器裡邊還有一個 servlet,你可以從一個 web 浏覽器中調用它。
類圖如下:
核心代碼如下:
HttpServer有兩個處理器,分别為ServletProcessor與StaticResourceProcessor。到底使用哪個,取決于分析到的uri的開頭。
在ServletProcessor中,會指定預設的檔案路徑,路徑下有servlet的class檔案,我們用URLClassLoader加載從uri中分析得到的servletname,得到servlet後,調用service方法即可。
在StaticResourceProcessor中,直接調用Response的sendStaticResource方法。
不過這裡有些問題
Request方法會作為參數被傳遞到servelt中,而Request類裡面有public型的parse方法與sendStaticResource方法,但是這兩個方法不應該在servlet中被調用!總不能把兩個方法改為private吧.一種方法是将兩個方法的通路限制符置空,就是預設的限制符,它是不能在包外被通路的。
不過還有另一種方法,門面模式
如下圖:
RequestFacade類接收一個Request對象傳遞給其成員變量ServletRequest,
public class RequestFacade implements ServletRequest {
private ServletRequest request = null;
public RequestFacade(Request request) {
this.request = request;
}
/* implementation of the ServletRequest*/
public Object getAttribute(String attribute) {
return request.getAttribute(attribute);
}
}
看到了吧,RequestFacade隻是一個二傳手,不過裡面根本就沒有parse方法。是以把RequestFacade作為參數傳遞給servlet是安全的。
是以,以後什麼地方要用parse方法,就給它傳Request對象;不能用parse的地方就傳RequestFacade。
第三章 連接配接器
第3章介紹了一個簡化版本的Tomcat 4預設連接配接器。這章裡邊的程式提供了一個學習工具,用于了解第 4 章裡邊的讨論的連接配接器。
本章類圖
這裡的HttpConnector做的工作就建立一個套接字,然後傳遞給HttpProcessor,在HttpProcessor的process方法中
parseRequest(input, output);
parseHeaders(input);
以上兩個方法是最重要的;
這一章最複雜的地方其實在于解析HTTP請求
可以分為5步:
讀取套接字的輸入流;
解析請求行
解析請求頭
解析cookie
擷取參數
後面的代碼如下:
parseRequest(input, output);
parseHeaders(input);
//check if this is a request for a servlet or a static resource
//a request for a servlet begins with "/servlet/"
if (request.getRequestURI().startsWith("/servlet/")) {
ServletProcessor processor = new ServletProcessor();
processor.process(request, response);
}
else {
StaticResourceProcessor processor = new StaticResourceProcessor();
processor.process(request, response);
}
分析完http請求,把它交給ServletProcessor或者StaticResourceProcessor即可。
第四章 tomcat預設的連接配接器
第 4 章介紹了 Tomcat 4 的預設連接配接器。這個連接配接器已經不推薦使用,推薦使用一個更快的連接配接器,Coyote。不過,預設的連接配接器更簡單,更易于了解。
在這一章裡,即引入了連接配接器的概念,也引入了容器的概念。咱們慢慢說,先看uml圖。
先說連接配接器,在第三章的簡易連接配接器裡,我們隻有一個HttpProcessor,在這一章裡,我們有了一個Processor連接配接池,這樣的好處就是我們同時可以處理多個請求了!
另一方面,這裡在解析請求頭的時候,使用的是字元數組來代替字元串。為什麼?效率高?效率為什麼高?自己看源碼找資料。(我怎麼覺得自己好賴皮呀)
這裡newProcessor與createProcessor的差別在于
newProcessor一定會産生一個新的HttpProcessor;
而createProcessor大部分情況是從processor池中拿;
httpprcessor啟動後,(在run方法中)會調用
process(socket);
待通過分析socket,把httprequest填充完畢後,
connector.getContainer().invoke(request, response);
連接配接器的任務就算是完成了!