一、先從servlet容器說起:大家最為熟悉的servlet容器就是tomcat ,servlet 容器是如何管理 servlet?
先看一下tomcat的容器模型:
從上圖可以看出 tomcat 的容器分為四個等級,真正管理servlet 的容器是context 容器,一個 context 對應一個 web 工程
tomcat 的容器等級中,context 容器是直接管理 servlet 在容器中的包裝類wrapper(standardwrapper)的容器,所以 context 容器如何運行將直接影響 servlet 的工作方式。
這里解釋一下servlet的包裝類:standardwrapper,這里有個疑問,為什么要將 servlet 包裝成 standardwrapper 而不直接是 servlet 對象。因為standardwrapper 是 tomcat 容器中的一部分,它具有容器的特征,而 servlet 為一個獨立的 web 開發標準,不應該強耦合在 tomcat 中。
除了將 servlet 包裝成 standardwrapper 并作為子容器添加到 context 中,其它的所有 web.xml 屬性都被解析到 context 中,所以說 context 容器才是真正運行 servlet 的 servlet 容器。一個 web 應用對應一個 context 容器,容器的配置屬性由應用的 web.xml 指定,這樣我們就能理解 web.xml 到底起到什么作用了
二、下面簡述一下servlet的工作工程:
web服務器在與客戶端交互時.servlet的工作過程是:
1.在客戶端對web服務器發出請求
2.web服務器接收到請求后將其發送給servlet
3.servlet容器為此產生一個實例對象并調用servletapi中相應的方法來對客戶端http請求進行處理,然后將處理的響應結果返回給web服務器.
4.web服務器將從servlet實例對象中收到的響應結構發送回客戶端.
三、servlet的生命周期:
如上圖所示,servlet的生命周期可以分為四個階段,即裝載類及創建實例階段、初始化階段、服務階段和實例銷毀階段。下面針對每個階段的編程任務及注意事項進行詳細的說明。
1、創建servlet實例:
在默認情況下servlet實例是在第一個請求到來的時候創建,以后復用。如果有的servlet需要復雜的操作需要載初始化時完成,比如打開文件、初始化網絡連接等,可以通知服務器在啟動的時候創建該servlet的實例。具體配置如下:
1
2
3
4
5
|
<servlet> <servlet-name>timeservlet</servlet-name> <servlet- class >com.allanlxf.servlet.basic.timeservlet</servlet- class > <load-on-startup> 1 </load-on-startup> </servlet> |
創建servlet對象的相關類結構:
2、初始化
一旦servlet實例被創建,web服務器會自動調用init(servletconfig config)方法來初始化該servlet。其中方法參數config中包含了servlet的配置信息,比如初始化參數,該對象由服務器創建。
i.如何配置servlet的初始化參數?
在web.xml中該servlet的定義標記中,比如:
1
2
3
4
5
6
7
8
9
10
11
12
|
<servlet> <servlet-name>timeservlet</servlet-name> <servlet- class >com.allanlxf.servlet.basic.timeservlet</servlet- class > <init-param> <param-name>user</param-name> <param-value>username</param-value> </init-param> <init-param> <param-name>blog</param-name> <param-value>http: //。。。</param-value> </init-param> </servlet> |
配置了兩個初始化參數user和blog它們的值分別為username和http://。。。, 這樣以后要修改用戶名和博客的地址不需要修改servlet代碼,只需修改配置文件即可。
ii.如何讀取servlet的初始化參數?
servletconfig中定義了如下的方法用來讀取初始化參數的信息:
public string getinitparameter(string name)
參數:初始化參數的名稱。
返回:初始化參數的值,如果沒有配置,返回null。
iii.init(servletconfig)方法執行次數
在servlet的生命周期中,該方法執行一次。
iv.init(servletconfig)方法與線程
該方法執行在單線程的環境下,因此開發者不用考慮線程安全的問題。
v.init(servletconfig)方法與異常
該方法在執行過程中可以拋出servletexception來通知web服務器servlet實例初始化失敗。一旦servletexception拋出,web服務器不會將客戶端請求交給該servlet實例來處理,而是報告初始化失敗異常信息給客戶端,該servlet實例將被從內存中銷毀。如果在來新的請求,web服務器會創建新的servlet實例,并執行新實例的初始化操作
3、服務
一旦servlet實例成功創建及初始化,該servlet實例就可以被服務器用來服務于客戶端的請求并生成響應。在服務階段web服務器會調用該實例的service(servletrequest request, servletresponse response)方法,request對象和response對象有服務器創建并傳給servlet實例。request對象封裝了客戶端發往服務器端的信息,response對象封裝了服務器發往客戶端的信息。
i. service()方法的職責
service()方法為servlet的核心方法,客戶端的業務邏輯應該在該方法內執行,典型的服務方法的開發流程為:
解析客戶端請求-〉執行業務邏輯-〉輸出響應頁面到客戶端
ii.service()方法與線程
為了提高效率,servlet規范要求一個servlet實例必須能夠同時服務于多個客戶端請求,即service()方法運行在多線程的環境下,servlet開發者必須保證該方法的線程安全性。
iii.service()方法與異常
service()方法在執行的過程中可以拋出servletexception和ioexception。其中servletexception可以在處理客戶端請求的過程中拋出,比如請求的資源不可用、數據庫不可用等。一旦該異常拋出,容器必須回收請求對象,并報告客戶端該異常信息。ioexception表示輸入輸出的錯誤,編程者不必關心該異常,直接由容器報告給客戶端即可。
編程注意事項說明:
1) 當server thread線程執行servlet實例的init()方法時,所有的client service thread線程都不能執行該實例的service()方法,更沒有線程能夠執行該實例的destroy()方法,因此servlet的init()方法是工作在單線程的環境下,開發者不必考慮任何線程安全的問題。
2) 當服務器接收到來自客戶端的多個請求時,服務器會在單獨的client service thread線程中執行servlet實例的service()方法服務于每個客戶端。此時會有多個線程同時執行同一個servlet實例的service()方法,因此必須考慮線程安全的問題。
3) 請大家注意,雖然service()方法運行在多線程的環境下,并不一定要同步該方法。而是要看這個方法在執行過程中訪問的資源類型及對資源的訪問方式。分析如下:
i. 如果service()方法沒有訪問servlet的成員變量也沒有訪問全局的資源比如靜態變量、文件、數據庫連接等,而是只使用了當前線程自己的資源,比如非指向全局資源的臨時變量、request和response對象等。該方法本身就是線程安全的,不必進行任何的同步控制。
ii. 如果service()方法訪問了servlet的成員變量,但是對該變量的操作是只讀操作,該方法本身就是線程安全的,不必進行任何的同步控制。
iii. 如果service()方法訪問了servlet的成員變量,并且對該變量的操作既有讀又有寫,通常需要加上同步控制語句。
iv. 如果service()方法訪問了全局的靜態變量,如果同一時刻系統中也可能有其它線程訪問該靜態變量,如果既有讀也有寫的操作,通常需要加上同步控制語句。
v. 如果service()方法訪問了全局的資源,比如文件、數據庫連接等,通常需要加上同步控制語句。
4、銷毀
當web服務器認為servlet實例沒有存在的必要了,比如應用重新裝載,或服務器關閉,以及servlet很長時間都沒有被訪問過。服務器可以從內存中銷毀(也叫卸載)該實例。web服務器必須保證在卸載servlet實例之前調用該實例的destroy()方法,以便回收servlet申請的資源或進行其它的重要的處理。
web服務器必須保證調用destroy()方法之前,讓所有正在運行在該實例的service()方法中的線程退出或者等待這些線程一段時間。一旦destroy()方法已經執行,web服務器將拒絕所有的新到來的對該servlet實例的請求,destroy()方法退出,該servlet實例即可以被垃圾回收。
四、servlet解析客戶端http請求流程圖:
1.web客戶向servlet容器發出http請求;
2.servlet容器解析web的http請求.
3.servlet容器創建一個httprequest對象,在這個對象中封裝了http請求信息;
4.servlet容器創建一個httpresponse對象;
5.servlet容器(如果訪問的該servlet不是在服務器啟動時創建的,則先創建servlet實例并調用init()方法初始化對象)調用httpservlet的service()方法,把httprequest和httpresponse對象為service方法的參數傳給httpservlet對象;
6.httpservlet調用httprequest的有關方法,獲取http請求信息;
7.httpservlet調用httpresponse的有關方法,生成響應數據;
8.servlet容器把httpservlet的響應結果傳給web客戶.
以上這篇基于servlet的執行原理與生命周期(全面解析)就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/weixb_2012/article/details/78898820