基于servlet的執(zhí)行原理與生命周期(全面解析)
一、先從servlet容器說(shuō)起:大家最為熟悉的servlet容器就是Tomcat ,Servlet 容器是如何管理 Servlet?
先看一下tomcat的容器模型:

從上圖可以看出 Tomcat 的容器分為四個(gè)等級(jí),真正管理Servlet 的容器是Context 容器,一個(gè) Context 對(duì)應(yīng)一個(gè) Web 工程
Tomcat 的容器等級(jí)中,Context 容器是直接管理 Servlet 在容器中的包裝類(lèi)Wrapper(StandardWrapper)的容器,所以 Context 容器如何運(yùn)行將直接影響 Servlet 的工作方式。
這里解釋一下servlet的包裝類(lèi):StandardWrapper,這里有個(gè)疑問(wèn),為什么要將 Servlet 包裝成 StandardWrapper 而不直接是 Servlet 對(duì)象。因?yàn)镾tandardWrapper 是 Tomcat 容器中的一部分,它具有容器的特征,而 Servlet 為一個(gè)獨(dú)立的 web 開(kāi)發(fā)標(biāo)準(zhǔn),不應(yīng)該強(qiáng)耦合在 Tomcat 中。
除了將 Servlet 包裝成 StandardWrapper 并作為子容器添加到 Context 中,其它的所有 web.xml 屬性都被解析到 Context 中,所以說(shuō) Context 容器才是真正運(yùn)行 Servlet 的 Servlet 容器。一個(gè) Web 應(yīng)用對(duì)應(yīng)一個(gè) Context 容器,容器的配置屬性由應(yīng)用的 web.xml 指定,這樣我們就能理解 web.xml 到底起到什么作用了
二、下面簡(jiǎn)述一下servlet的工作工程:
Web服務(wù)器在與客戶(hù)端交互時(shí).Servlet的工作過(guò)程是:
1.在客戶(hù)端對(duì)web服務(wù)器發(fā)出請(qǐng)求
2.web服務(wù)器接收到請(qǐng)求后將其發(fā)送給Servlet
3.Servlet容器為此產(chǎn)生一個(gè)實(shí)例對(duì)象并調(diào)用ServletAPI中相應(yīng)的方法來(lái)對(duì)客戶(hù)端HTTP請(qǐng)求進(jìn)行處理,然后將處理的響應(yīng)結(jié)果返回給WEB服務(wù)器.
4.web服務(wù)器將從Servlet實(shí)例對(duì)象中收到的響應(yīng)結(jié)構(gòu)發(fā)送回客戶(hù)端.

三、servlet的生命周期:

如上圖所示,Servlet的生命周期可以分為四個(gè)階段,即裝載類(lèi)及創(chuàng)建實(shí)例階段、初始化階段、服務(wù)階段和實(shí)例銷(xiāo)毀階段。下面針對(duì)每個(gè)階段的編程任務(wù)及注意事項(xiàng)進(jìn)行詳細(xì)的說(shuō)明。
1、創(chuàng)建servlet實(shí)例:
在默認(rèn)情況下Servlet實(shí)例是在第一個(gè)請(qǐng)求到來(lái)的時(shí)候創(chuàng)建,以后復(fù)用。如果有的Servlet需要復(fù)雜的操作需要載初始化時(shí)完成,比如打開(kāi)文件、初始化網(wǎng)絡(luò)連接等,可以通知服務(wù)器在啟動(dòng)的時(shí)候創(chuàng)建該Servlet的實(shí)例。具體配置如下:
<servlet> <servlet-name>TimeServlet</servlet-name> <servlet-class>com.allanlxf.servlet.basic.TimeServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
創(chuàng)建servlet對(duì)象的相關(guān)類(lèi)結(jié)構(gòu):

2、初始化
一旦Servlet實(shí)例被創(chuàng)建,Web服務(wù)器會(huì)自動(dòng)調(diào)用init(ServletConfig config)方法來(lái)初始化該Servlet。其中方法參數(shù)config中包含了Servlet的配置信息,比如初始化參數(shù),該對(duì)象由服務(wù)器創(chuàng)建。
I.如何配置Servlet的初始化參數(shù)?
在web.xml中該Servlet的定義標(biāo)記中,比如:
<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>
配置了兩個(gè)初始化參數(shù)user和blog它們的值分別為username和http://。。。, 這樣以后要修改用戶(hù)名和博客的地址不需要修改Servlet代碼,只需修改配置文件即可。
II.如何讀取Servlet的初始化參數(shù)?
ServletConfig中定義了如下的方法用來(lái)讀取初始化參數(shù)的信息:
public String getInitParameter(String name)
參數(shù):初始化參數(shù)的名稱(chēng)。
返回:初始化參數(shù)的值,如果沒(méi)有配置,返回null。
III.init(ServletConfig)方法執(zhí)行次數(shù)
在Servlet的生命周期中,該方法執(zhí)行一次。
IV.init(ServletConfig)方法與線(xiàn)程
該方法執(zhí)行在單線(xiàn)程的環(huán)境下,因此開(kāi)發(fā)者不用考慮線(xiàn)程安全的問(wèn)題。
V.init(ServletConfig)方法與異常
該方法在執(zhí)行過(guò)程中可以?huà)伋鯯ervletException來(lái)通知Web服務(wù)器Servlet實(shí)例初始化失敗。一旦ServletException拋出,Web服務(wù)器不會(huì)將客戶(hù)端請(qǐng)求交給該Servlet實(shí)例來(lái)處理,而是報(bào)告初始化失敗異常信息給客戶(hù)端,該Servlet實(shí)例將被從內(nèi)存中銷(xiāo)毀。如果在來(lái)新的請(qǐng)求,Web服務(wù)器會(huì)創(chuàng)建新的Servlet實(shí)例,并執(zhí)行新實(shí)例的初始化操作
3、服務(wù)
一旦Servlet實(shí)例成功創(chuàng)建及初始化,該Servlet實(shí)例就可以被服務(wù)器用來(lái)服務(wù)于客戶(hù)端的請(qǐng)求并生成響應(yīng)。在服務(wù)階段Web服務(wù)器會(huì)調(diào)用該實(shí)例的service(ServletRequest request, ServletResponse response)方法,request對(duì)象和response對(duì)象有服務(wù)器創(chuàng)建并傳給Servlet實(shí)例。request對(duì)象封裝了客戶(hù)端發(fā)往服務(wù)器端的信息,response對(duì)象封裝了服務(wù)器發(fā)往客戶(hù)端的信息。
I. service()方法的職責(zé)
service()方法為Servlet的核心方法,客戶(hù)端的業(yè)務(wù)邏輯應(yīng)該在該方法內(nèi)執(zhí)行,典型的服務(wù)方法的開(kāi)發(fā)流程為:
解析客戶(hù)端請(qǐng)求-〉執(zhí)行業(yè)務(wù)邏輯-〉輸出響應(yīng)頁(yè)面到客戶(hù)端
II.service()方法與線(xiàn)程
為了提高效率,Servlet規(guī)范要求一個(gè)Servlet實(shí)例必須能夠同時(shí)服務(wù)于多個(gè)客戶(hù)端請(qǐng)求,即service()方法運(yùn)行在多線(xiàn)程的環(huán)境下,Servlet開(kāi)發(fā)者必須保證該方法的線(xiàn)程安全性。
III.service()方法與異常
service()方法在執(zhí)行的過(guò)程中可以?huà)伋鯯ervletException和IOException。其中ServletException可以在處理客戶(hù)端請(qǐng)求的過(guò)程中拋出,比如請(qǐng)求的資源不可用、數(shù)據(jù)庫(kù)不可用等。一旦該異常拋出,容器必須回收請(qǐng)求對(duì)象,并報(bào)告客戶(hù)端該異常信息。IOException表示輸入輸出的錯(cuò)誤,編程者不必關(guān)心該異常,直接由容器報(bào)告給客戶(hù)端即可。
編程注意事項(xiàng)說(shuō)明:
1) 當(dāng)Server Thread線(xiàn)程執(zhí)行Servlet實(shí)例的init()方法時(shí),所有的Client Service Thread線(xiàn)程都不能執(zhí)行該實(shí)例的service()方法,更沒(méi)有線(xiàn)程能夠執(zhí)行該實(shí)例的destroy()方法,因此Servlet的init()方法是工作在單線(xiàn)程的環(huán)境下,開(kāi)發(fā)者不必考慮任何線(xiàn)程安全的問(wèn)題。
2) 當(dāng)服務(wù)器接收到來(lái)自客戶(hù)端的多個(gè)請(qǐng)求時(shí),服務(wù)器會(huì)在單獨(dú)的Client Service Thread線(xiàn)程中執(zhí)行Servlet實(shí)例的service()方法服務(wù)于每個(gè)客戶(hù)端。此時(shí)會(huì)有多個(gè)線(xiàn)程同時(shí)執(zhí)行同一個(gè)Servlet實(shí)例的service()方法,因此必須考慮線(xiàn)程安全的問(wèn)題。
3) 請(qǐng)大家注意,雖然service()方法運(yùn)行在多線(xiàn)程的環(huán)境下,并不一定要同步該方法。而是要看這個(gè)方法在執(zhí)行過(guò)程中訪(fǎng)問(wèn)的資源類(lèi)型及對(duì)資源的訪(fǎng)問(wèn)方式。分析如下:
i. 如果service()方法沒(méi)有訪(fǎng)問(wèn)Servlet的成員變量也沒(méi)有訪(fǎng)問(wèn)全局的資源比如靜態(tài)變量、文件、數(shù)據(jù)庫(kù)連接等,而是只使用了當(dāng)前線(xiàn)程自己的資源,比如非指向全局資源的臨時(shí)變量、request和response對(duì)象等。該方法本身就是線(xiàn)程安全的,不必進(jìn)行任何的同步控制。
ii. 如果service()方法訪(fǎng)問(wèn)了Servlet的成員變量,但是對(duì)該變量的操作是只讀操作,該方法本身就是線(xiàn)程安全的,不必進(jìn)行任何的同步控制。
iii. 如果service()方法訪(fǎng)問(wèn)了Servlet的成員變量,并且對(duì)該變量的操作既有讀又有寫(xiě),通常需要加上同步控制語(yǔ)句。
iv. 如果service()方法訪(fǎng)問(wèn)了全局的靜態(tài)變量,如果同一時(shí)刻系統(tǒng)中也可能有其它線(xiàn)程訪(fǎng)問(wèn)該靜態(tài)變量,如果既有讀也有寫(xiě)的操作,通常需要加上同步控制語(yǔ)句。
v. 如果service()方法訪(fǎng)問(wèn)了全局的資源,比如文件、數(shù)據(jù)庫(kù)連接等,通常需要加上同步控制語(yǔ)句。
4、銷(xiāo)毀
當(dāng)Web服務(wù)器認(rèn)為Servlet實(shí)例沒(méi)有存在的必要了,比如應(yīng)用重新裝載,或服務(wù)器關(guān)閉,以及Servlet很長(zhǎng)時(shí)間都沒(méi)有被訪(fǎng)問(wèn)過(guò)。服務(wù)器可以從內(nèi)存中銷(xiāo)毀(也叫卸載)該實(shí)例。Web服務(wù)器必須保證在卸載Servlet實(shí)例之前調(diào)用該實(shí)例的destroy()方法,以便回收Servlet申請(qǐng)的資源或進(jìn)行其它的重要的處理。
Web服務(wù)器必須保證調(diào)用destroy()方法之前,讓所有正在運(yùn)行在該實(shí)例的service()方法中的線(xiàn)程退出或者等待這些線(xiàn)程一段時(shí)間。一旦destroy()方法已經(jīng)執(zhí)行,Web服務(wù)器將拒絕所有的新到來(lái)的對(duì)該Servlet實(shí)例的請(qǐng)求,destroy()方法退出,該Servlet實(shí)例即可以被垃圾回收。
四、servlet解析客戶(hù)端http請(qǐng)求流程圖:

1.web客戶(hù)向Servlet容器發(fā)出HTTP請(qǐng)求;
2.Servlet容器解析web的HTTP請(qǐng)求.
3.Servlet容器創(chuàng)建一個(gè)HttpRequest對(duì)象,在這個(gè)對(duì)象中封裝了http請(qǐng)求信息;
4.Servlet容器創(chuàng)建一個(gè)HttpResponse對(duì)象;
5.Servlet容器(如果訪(fǎng)問(wèn)的該servlet不是在服務(wù)器啟動(dòng)時(shí)創(chuàng)建的,則先創(chuàng)建servlet實(shí)例并調(diào)用init()方法初始化對(duì)象)調(diào)用HttpServlet的service()方法,把HttpRequest和HttpResponse對(duì)象為service方法的參數(shù)傳給HttpServlet對(duì)象;
6.HttpServlet調(diào)用HttpRequest的有關(guān)方法,獲取HTTP請(qǐng)求信息;
7.HttpServlet調(diào)用HttpResponse的有關(guān)方法,生成響應(yīng)數(shù)據(jù);
8.Servlet容器把HttpServlet的響應(yīng)結(jié)果傳給web客戶(hù).
以上這篇基于servlet的執(zhí)行原理與生命周期(全面解析)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳細(xì)介紹Java關(guān)鍵字throw?throws?Throwable的用法與區(qū)別
這篇文章主要介紹了java中throws與throw及Throwable的用法和區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
java+mysql模擬實(shí)現(xiàn)銀行系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java+mysql模擬實(shí)現(xiàn)銀行系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
springboot利用AOP完成日志統(tǒng)計(jì)的詳細(xì)步驟
項(xiàng)目用到了過(guò)濾器,可能有的人會(huì)不理解,之所以用過(guò)濾器是因?yàn)橄胍谌罩居涗沺ost請(qǐng)求的json數(shù)據(jù)。本文重點(diǎn)給大家介紹springboot利用AOP完成日志統(tǒng)計(jì)的詳細(xì)步驟,感興趣的朋友跟隨小編一起看看吧2021-12-12
java面試題解LeetCode27二叉樹(shù)的鏡像實(shí)例
這篇文章主要為大家介紹了java面試題解LeetCode27二叉樹(shù)的鏡像實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Springboot GET和POST請(qǐng)求參數(shù)獲取方式小結(jié)
Spring Boot GET和POST請(qǐng)求參數(shù)獲取是開(kāi)發(fā)人員經(jīng)常需要解決的問(wèn)題,本文主要介紹了Springboot GET和POST請(qǐng)求參數(shù)獲取方式小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09
mybatis?一對(duì)多映射?column屬性的注意事項(xiàng)說(shuō)明
這篇文章主要介紹了mybatis?一對(duì)多映射?column屬性的注意事項(xiàng)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。2022-01-01
如何解決Springboot?Dao注入失敗的問(wèn)題
這篇文章主要介紹了如何解決Spring?boot?Dao注入失敗的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
使用Mybatis-Plus時(shí)的SqlSessionFactory問(wèn)題及處理
這篇文章主要介紹了使用Mybatis-Plus時(shí)的SqlSessionFactory問(wèn)題及處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
java中Class.getMethods()和Class.getDeclaredMethods()方法的區(qū)別
這篇文章主要介紹了java中Class.getMethods()和Class.getDeclaredMethods()方法的區(qū)別 ,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09

