本文來自:Linux教程 -- http://doc.linuxpk.com/45432.html
servlet有良好的生存期的定義,包括如何加載、執行個體化、初始化、處理用戶端請求以及如何被移除。這個生存期由javax.servlet.Servlet接口的init,service和destroy方法表達。
1、加載和執行個體化
容器負責加載和執行個體化一個servlet。執行個體化和加載可以發生在引擎啟動的時候,也可以推遲到容器需要該servlet為客戶請求服務的時候。
首先容器必須先定位servlet類,在必要的情況下,容器使用通常的Java類加載工具加載該servlet,可能是從本機檔案系統,也可以是從遠端
檔案系統甚至其它的網絡服務。容器加載servlet類以後,它會執行個體化該類的一個執行個體。需要注意的是可能會執行個體化多個執行個體,例如一個servlet類因
為有不同的初始參數而有多個定義,或者servlet實作SingleThreadModel而導緻容器為之生成一個執行個體池。
2、初始化
servlet加載并執行個體化後,容器必須在它能夠處理用戶端請求前初始化它。初始化的過程主要是讀取永久的配置資訊,昂貴資源(例如JDBC連接配接)以及
其它僅僅需要執行一次的任務。通過調用它的init方法并給它傳遞唯一的一個(每個servlet定義一個)ServletConfig對象完成這個過
程。給它傳遞的這個配置對象允許servlet通路容器的配置資訊中的名稱-值對(name-value)初始化參數。這個配置對象同時給servlet
提供了通路實作了ServletContext接口的具體對象的方法,該對象描述了servlet的運作環境。
2.1初始化的錯誤處理
在初始化期間,servlet執行個體可能通過抛出UnavailableException 或者
ServletException異常表明它不能進行有效服務。如果一個servlet抛出一個這樣的異常,它将不會被置入有效服務并且應該被容器立即釋
放。在此情況下destroy方法不會被調用因為初始化沒有成功完成。在失敗的執行個體被釋放後,容器可能在任何時候執行個體化一個新的執行個體,對這個規則的唯一例
外是如果失敗的servlet抛出的異常是UnavailableException并且該異常指出了最小的無效時間,那麼容器就會至少等待該時間指明的
時限才會重新試圖建立一個新的執行個體。
2.2、工具因素
當工具(注:根據筆者的了解,這個工具可能是應用伺服器的
某些檢查工具,通常是驗證應用的合法性和完整性)加載和内省(introspect)一個web應用時,它可能加載和内省該應用中的類,這個行為将觸發那
些類的靜态初始方法被執行,是以,開發者不能假定隻要當servlet的init方法被調用後它才處于活動容器運作狀态(active
container
runtime)。作為一個例子,這意味着servlet不能在它的靜态(類)初始化方法被調用時試圖建立資料庫連接配接或者連接配接EJB容器。
3、處理請求
在servlet被适當地初始化後,容器就可以使用它去處理請求了。每一個請求由ServletRequest類型的對象代表,而servlet使用
ServletResponse回應該請求。這些對象被作為service方法的參數傳遞給servlet。在HTTP請求的情況下,容器必須提供代表請
求和回應的HttpServletRequest和HttpServletResponse的具體實作。需要注意的是容器可能會建立一個servlet實
例并将之放入等待服務的狀态,但是這個執行個體在它的生存期中可能根本沒有處理過任何請求。
3.1、多線程問題
容器
可能同時将多個用戶端的請求發送給一個執行個體的service方法,這也就意味着開發者必須確定編寫的servlet可以處理并發問題。如果開發者想防止這
種預設的行為,那麼他可以讓他編寫的servlet實作SingleThreadModel。實作這個類可以保證一次隻會有一個線程在執行service
方法并且一次性執行完。容器可以通過将請求排隊或者維護一個servlet執行個體池滿足這一點。如果servlet是分布式應用的一部分,那麼,那麼容器可
能在該應用分布的每個JVM中都維護一個執行個體池。如果開發者使用synchronized關鍵字定義service方法(或者是doGet和
doPost),容器将排隊處理請求,這是由底層的java運作時系統要求的。我們強烈推薦開發者不要同步service方法或者HTTPServlet
的諸如doGet和doPost這樣的服務方法。
3.2、處理請求中的異常
servlet在對請求進行服務的時
候有可能抛出ServletException或者UnavailableException異常。ServletException表明在處理請求的過
程中發生了錯誤容器應該使用合适的方法清除該請求。UnavailableException表明servlet不能對請求進行處理,可能是暫時的,也可
能是永久的。如果UnavailableException指明是永久性的,那麼容器必須将servlet從服務中移除,調用它的destroy方法并釋
放它的執行個體。如果指明是暫時的,那麼容器可以選擇在異常資訊裡面指明的這個暫時無法服務的時間段裡面不向它發送任何請求。在這個時間段裡面被被拒絕的請求
必須使用SERVICE_UNAVAILABLE
(503)傳回狀态進行響應并且應該攜帶稍後重試(Retry-After)的響應頭表明不能服務隻是暫時的。容器也可以選擇不對暫時性和永久性的不可用
進行區分而全部當作永久性的并移除抛出異常的servlet。
3.3線程安全
開發者應該注意容器實作的請求和響
應對象(注:即容器實作的HttpServletRequest和HttpServletResponese)沒有被保證是線程安全的,這就意味着他們隻
能在請求處理線程的範圍内被使用,這些對象不能被其它執行線程所引用,因為引用的行為是不确定的。
4、服務結束
容器沒有被要求将一個加載的servlet儲存多長時間,是以一個servlet執行個體可能隻在容器中存活了幾毫秒,當然也可能是其它更長的任意時間(但是
肯定會短于容器的生存期)當容器決定将之移除時(原因可能是儲存記憶體資源或者自己被關閉),那麼它必須允許servlet釋放它正在使用的任何資源并儲存
任何永久狀态(這個過程通過調用destroy方法達到)。容器在能夠調用destroy方法前,它必須允許那些正在service方法中執行的線程執行
完或者在伺服器定義的一段時間内執行(這個時間段在容器調用destroy之前)。一旦destroy方法被調用,容器就不會再向該執行個體發送任何請求。如
果容器需要再使用該servlet,它必須建立新的執行個體。destroy方法完成後,容器必須釋放servlet執行個體以便它能夠被垃圾回收。
本文來自:Linux教程 -- http://doc.linuxpk.com/45432.html