2.4 Servlet的生命周期((life cycle)-------------------------------------------------------------------------------- 到目前為止,您已經(jīng)學(xué)習到了如何撰寫(xiě)、編譯與執行Servlet。由于所有的Servlet都必須執行于Servlet容器中,因此我們必須了解Servlet容器如何進(jìn)行下列工作:n 何時(shí)載入Servlet,并予以實(shí)體化(instantiated)n 如何回應用戶(hù)的請求n 何時(shí)該卸載Servlet的服務(wù)上述三個(gè)階段即構成Servlet的“生命周期”(life cycle)。值得注意的是,Servlet生命周期并不由程序員控制,而是由Servlet容器掌管。在javax.servlet.Servlet接口內定義了下面三個(gè)方法:n init()n service()n destroy()這意味著(zhù)所有的Servlet都會(huì )實(shí)現這三個(gè)方法,而Servlet容器可由此控制其生命周期。本節將深入探討這些方法的用途及使用時(shí)機。2.4.1 service()方法在某些情況下,Servlet容器需要將Servlet實(shí)體化(例如:Servlet容器接收到某個(gè)HTTP請求)。簡(jiǎn)單地說(shuō),實(shí)體化的過(guò)程就是建立一個(gè)新的Servlet,可簡(jiǎn)單地概分為下列兩個(gè)階段。(1) 在實(shí)體化Servlet以前,Servlet容器必須確認與Servlet有關(guān)的類(lèi)位于何處,再以“類(lèi)載入器”(ClassLoader)將Servlet類(lèi)載入存儲器。(2) 當Servlet被調用時(shí),Servlet容器將會(huì )調用該Servlet的默認構造函數(default constructor),然后建立一個(gè)Servlet實(shí)體。因為Servlet的構造函數是由Servlet容器調用的,所以Servlet類(lèi)不應該包含“非默認構造函數”(non-default constructor)。所謂的“非默認構造函數”是指可以傳遞參數的構造函數。此時(shí)您可能產(chǎn)生一個(gè)疑問(wèn):如果Servlet沒(méi)有“非默認構造函數”,如何將起始參數傳遞給Servlet呢?這問(wèn)題問(wèn)得好,在回答前,筆者先說(shuō)明何時(shí)需要將起始參數傳遞給Servlet。試想下列情境:某個(gè)Servlet需要通過(guò)JDBC存取數據庫。依照標準程序,您必須指定JDBC驅動(dòng)程序的種類(lèi)、目的數據庫位置以及登錄數據庫所使用的賬號與密碼,然后利用這些信息建立與數據庫的連接。然而將這些信息全部撰寫(xiě)在每個(gè)Servlet里面將造成一個(gè)潛在問(wèn)題:萬(wàn)一后端數據庫需要更換,所有Servlet程序碼豈不是要全部改寫(xiě)!由此可見(jiàn),比較妥善的方式應該是將所有Servlet都會(huì )存取的數據統一存放在某個(gè)位置,以便后續管理與維護。在Java Servlet技術(shù)所建構的Web應用程序中,每個(gè)Web應用程序均可定義一個(gè)部署描述文件:web.xml。該文件可存放Servlet所需要的起始參數(例如剛才提及的數據庫目的位置與用戶(hù)密碼)以及Web應用程序的結構數據。當Servlet容器讀取web.xml文件內容后,可以將這些起始參數封裝成一個(gè)對象,并在調用init()方法時(shí)傳遞給Servlet,這個(gè)做法即可達到初始化Servlet起始參數的目的。以下是javax.servlet.Servlet類(lèi)內定義的init()方法:public void init(ServletConfig config) throws ServletException{}由此可知:Servlet容器調用init()方法時(shí),將會(huì )傳入一個(gè)ServletConfig對象。因此我們可以在Servlet內覆寫(xiě)init()方法,并通過(guò)ServletConfig對象來(lái)取得某些起始參數。關(guān)于如何定義與存取Servlet起始參數,將留待第3章再做說(shuō)明。n 如何覆寫(xiě)init()方法如果您仔細研究了Servlet API的定義,也許會(huì )發(fā)現一個(gè)奇怪的現象:javax.servlet接口只定義了一個(gè)init()方法,但是javax.servlet.GenericServlet類(lèi)(繼承自javax.servlet)內卻定義了兩個(gè)init()方法(參考圖2-13),這個(gè)問(wèn)題倒是值得我們研究。由于javax.servlet接口內定義的init(ServletConfig config)方法必須傳入一個(gè)ServletConfig對象,因此在覆寫(xiě)該方法時(shí),必須再以super.init(config) 調用父類(lèi)的init()方法,這個(gè)步驟稍嫌繁瑣。為了簡(jiǎn)化init()方法的覆寫(xiě)方式,javax.servlet.GenericServlet類(lèi)另外定義了一個(gè)不需傳遞參數的init方法,以便程序員直接覆寫(xiě)init()方法。當Servlet容器調用init(ServletConfig config)方法時(shí),該方法也會(huì )自動(dòng)調用您所覆寫(xiě)的init()方法。提示:在GenericServlet類(lèi)內定義的init()方法并未傳入ServletConfig對象。如果在此方法內須要存取ServletConfig對象,可直接調用getServletConfig()方法。 圖2-13 GenericaServlet類(lèi)與Servlet接口2.4.2 service()方法當Servlet實(shí)體經(jīng)過(guò)初始化程序后,只要Servlet 容器接收到用戶(hù)傳送的請求,就會(huì )將這個(gè)請求封裝成ServletRequest對象,然后調用service()方法。以下是javax.servlet.Servlet接口所定義的service()方法。public void service(ServletRequest req, ServletResponse res) throws ServletException,java.io.IOException如果用戶(hù)傳送的是HTTP請求,Servlet容器就會(huì )將HTTP請求封裝成HttpServletRequest對象,然后調用service()方法。以下是在javax.servlet.http.HttpServlet類(lèi)中定義的service()方法:protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException,java.io.IOException針對HTTP請求,service()方法會(huì )根據HTTP請求形式(GET、POST、HEAD等)來(lái)決定應該執行哪種doXXX()方法。如前所述,如果HTTP請求形式為POST,service()方法將會(huì )自動(dòng)調用doPost()方法。因此在一般情況下,程序員無(wú)須去覆寫(xiě)service()方法,只須根據用戶(hù)可能傳送的HTTP形式去覆寫(xiě)doGet()與doPost()等方法即可。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。