幾個問題:
Servlet是什麼?Servlet容器是什麼??Tomcat是什麼???Tomcat的組成結構????Tomcat的工作模式?????
Servlet是什麼
爲了能讓Web服務器與Web應用這兩個不同的軟件系統協作,需要一套標準接口,Servlet就是其中最主要的一個接口。
- Web服務器可以訪問任意一個Web應用中實現Servlet接口的類。
- Web應用中被Web服務器動態調用的程序代碼位於Servlet接口的實現類中。
SUN公司制定了Web應用與Web服務器進行協作的一系列標準Java接口(統稱爲Java Servlet API),這一系列標準Java接口和規約統稱爲Servlet規範。
Servlet容器是什麼
在Servlet規範中,把能夠發佈和運行JavaWeb應用的Web服務器稱爲Servlet容器,他的最主要特稱是動態執行JavaWeb應用中的Servlet實現類中的程序代碼。
Tomcat是什麼
Tomcat是Servlet容器,同時也是輕量級的Web服務器。這是它的兩個身份!Apache Server、Microsoft IIS、Apache Tomcat都是Web服務器。Tomcat作爲Web服務器時,主要負責實現HTTP傳輸等工作。
Tomcat作爲Servlet容器時,主要負責解析Request,生成ServletRequest、ServletResponse,將其傳給相應的Servlet(調用service( )方法),再將Servlet的相應結果返回。
Tomcat組成結構
容器結構
服務訪問流程,一
服務訪問流程,二
Server,代表整個Servlet容器組件,是Tomcat的頂層元素。其中可以包含一到多個Service;
Service,包含一個Engine,以及一到多個Connector;
Connector,代表和客戶端程序實際交互的組件,負責接收客戶請求,以及向客戶返回響應結果;
Engine,處理同一個Service中所有Connector接收到的客戶請求;
Host,在Engine中可以包含多個Host,每個Host定義了一個虛擬主機,它可以包含一個到多個Web應用;
Context,一個Host中可以包含多個Context,每個Context代表了運行在虛擬主機上的單個Web應用;
再一次對照server.xml配置文件理解
Tomcat,web工程,Servlet的啓動
Service對外提供Web應用服務,而Service核心組件Container的靈魂便是Servlet容器。而真正管理Servlet的是Context容器。Context容器直接管理Servlet在容器中的包裝類Wrapper,一個Web應用對應一個Context容器。添加一個Web應用就會創建一個Context容器,並將這個Context容器加入到父容器Host中。
Tomcat 的啓動邏輯是基於觀察者模式設計的,所有的容器都會繼承 Lifecycle 接口,它管理着容器的整個生命週期,所有容器的的修改和狀態的改變都會由它去通知已經註冊的觀察者(Listener)。
Tomcat主要類的啓動時序圖:
當Context容器初始化狀態設爲init時,添加在Contex容器的Listener將會被調用。ContextConfig繼承了LifecycleListener接口,它被加載到StandardContext容器中。ContextConfig類會負責整個Web應用的配置文件的解析工作。ContextConfig的init方法將會主要完成以下工作:
- 創建用於解析xml配置文件的contextDigester對象
- 讀取默認context.xml配置文件,如果存在解析它
- 讀取默認Host配置文件,如果存在解析它
- 讀取默認Context自身的配置文件,如果存在解析它
- 設置Context的DocBase
ContextConfig的init方法完成後,Context容器的會執行startInternal方法,這個方法啓動邏輯比較複雜,主要包括如下幾個部分:
- 創建讀取資源文件的對象
- 創建ClassLoader對象
- 設置應用的工作目錄
- 啓動相關的輔助類如:logger、realm、resources等
- 修改啓動狀態,通知感興趣的觀察者(Web應用的配置)
- 子容器的初始化
- 獲取ServletContext並設置必要的參數
- 初始化“loadonstartup”的Servlet
web應用的初始化
web的初始化是在contextConfig中實現的,應用的初始化主要是對web.xml進行解析,這個文件描述了Web應用的關鍵信息,也是整個Web應用的入口。Tomcat將web.xml文件解析後,將其中的屬性設置到Context容器中,這裏包括創建Servlet實例,Filter和Listener。將Servlet包裝成Context中的包裝類Wrapper。
創建Servlet實例
如果Servlet在web.xml中load-on-startup的配置大於0,那麼在Context容器啓動時就會被實例化。
Servlet初始化
初始化 Servlet 在 StandardWrapper 的 initServlet 方法中,這個方法就是調用 Servlet 的 init 的方法,同時把包裝了 StandardWrapper 對象的 StandardWrapperFacade 作爲 ServletConfig 傳給 Servlet。
如果該 Servlet 關聯的是一個 jsp 文件,那麼前面初始化的就是 JspServlet,接下去會模擬一次簡單請求,請求調用這個 jsp 文件,以便編譯這個 jsp 文件爲 class,並初始化這個 class。這樣
Servlet 對象就初始化完成了,事實上 Servlet 從被 web.xml 中解析到完成初始化,這個過程非常複雜,中間有很多過程,包括各種容器狀態的轉化引起的監聽事件的觸發、各種訪問權限的控制和一些不可預料的錯誤發生的判斷行爲等等。
Servlet的初始化時序圖:
Servlet頂層類關聯圖:
Servlet如何工作
清楚了Servlet是如何被加載以及被初始化的,以及Servlet的體系結構,現在的問題就是它如何被調用。
當用戶從瀏覽器向服務器發起一個請求,通常會包含如下信息:http://hostname:port/contextpath/servletpath。
hostname和port是用來與服務器建立TCP連接,而後面的URL纔是用來選擇服務器中那個子容器服務用戶的請求。服務器由org.apache.tomcat.util.http.mapper完成映射工作,根據這個URL來達到正確的Servlet容器中,這個類保存了Tomcat的Container容器中的所有子容器的信息,當org.apache.catalina.connector.Request類在進入Container容器之前,mapper將會根據這次請求的hostnane和contextpath將host和context容器設置到Request的mappingData屬性中。所以當Request進入Container容器之前,它要訪問那個子容器這時就已經確定了。
請求執行過程