天天看點

how tomcat works 總結

希望各位網友在看完<<how tomcat works>>一書或者鄙人的tomcat專欄文章後再看這篇部落格

這裡主要是梳理各個章節的核心概念

第一章 一個簡單的Web伺服器

第1章從這本書一開始就介紹了一個簡單的HTTP伺服器。要建立一個可工作的HTTP伺服器,你需要知道在 java.net 包裡邊的 2 個類的内部運作:Socket 和 ServerSocket。這裡有關于這 2個類足夠的背景資料,使得你能夠了解附帶程式是如何工作的。

類圖如下:

how tomcat works 總結

程式的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 浏覽器中調用它。

類圖如下:

how tomcat works 總結

核心代碼如下:

how tomcat works 總結

HttpServer有兩個處理器,分别為ServletProcessor與StaticResourceProcessor。到底使用哪個,取決于分析到的uri的開頭。

在ServletProcessor中,會指定預設的檔案路徑,路徑下有servlet的class檔案,我們用URLClassLoader加載從uri中分析得到的servletname,得到servlet後,調用service方法即可。

在StaticResourceProcessor中,直接調用Response的sendStaticResource方法。

不過這裡有些問題

Request方法會作為參數被傳遞到servelt中,而Request類裡面有public型的parse方法與sendStaticResource方法,但是這兩個方法不應該在servlet中被調用!總不能把兩個方法改為private吧.一種方法是将兩個方法的通路限制符置空,就是預設的限制符,它是不能在包外被通路的。

不過還有另一種方法,門面模式

如下圖:

how tomcat works 總結

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 章裡邊的讨論的連接配接器。

本章類圖

how tomcat works 總結

這裡的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圖。

how tomcat works 總結

先說連接配接器,在第三章的簡易連接配接器裡,我們隻有一個HttpProcessor,在這一章裡,我們有了一個Processor連接配接池,這樣的好處就是我們同時可以處理多個請求了!

另一方面,這裡在解析請求頭的時候,使用的是字元數組來代替字元串。為什麼?效率高?效率為什麼高?自己看源碼找資料。(我怎麼覺得自己好賴皮呀)

這裡newProcessor與createProcessor的差別在于

newProcessor一定會産生一個新的HttpProcessor;

而createProcessor大部分情況是從processor池中拿;

httpprcessor啟動後,(在run方法中)會調用

process(socket);      

待通過分析socket,把httprequest填充完畢後,

connector.getContainer().invoke(request, response);      

連接配接器的任務就算是完成了!