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