轉(zhuǎn)帖|行業(yè)資訊|編輯:郝浩|2016-08-31 15:39:19.000|閱讀 382 次
概述:很多時(shí)候我們都想知道,web容器或web服務(wù)器(比如Tomcat或者jboss)是怎樣工作的?它們是怎樣處理來(lái)自全世界的http請(qǐng)求的?它們?cè)谀缓笞隽耸裁磩?dòng)作?Java Servlet API(例如ServletContext,ServletRequest,ServletResponse和Session這些類)在其中扮演了什么角色?這些都是web應(yīng)用開(kāi)發(fā)者或者想成為web應(yīng)用開(kāi)發(fā)者的人必須要知道的重要問(wèn)題或概念。在這篇文章里,我將會(huì)盡量給出以上某些問(wèn)題的答案。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
很多時(shí)候我們都想知道,web容器或web服務(wù)器(比如Tomcat或者jboss)是怎樣工作的?它們是怎樣處理來(lái)自全世界的http請(qǐng)求的?它們?cè)谀缓笞隽耸裁磩?dòng)作?Java Servlet API(例如ServletContext,ServletRequest,ServletResponse和Session這些類)在其中扮演了什么角色?這些都是web應(yīng)用開(kāi)發(fā)者或者想成為web應(yīng)用開(kāi)發(fā)者的人必須要知道的重要問(wèn)題或概念。在這篇文章里,我將會(huì)盡量給出以上某些問(wèn)題的答案。
我先討論web服務(wù)器和應(yīng)用服務(wù)器。讓我在用一句話大概講講:
“在過(guò)去它們是有區(qū)別的,但是這兩個(gè)不同的分類慢慢地合并了,而如今在大多在情況下和使用中可以把它們看成一個(gè)整體。”
在Mosaic瀏覽器(通常被認(rèn)為是第一個(gè)圖形化的web瀏覽器)和超鏈接內(nèi)容的初期,演變出了“web服務(wù)器”的新概念,它通過(guò)HTTP協(xié)議來(lái)提供靜態(tài)頁(yè)面內(nèi)容和圖片服務(wù)。在那個(gè)時(shí)候,大多數(shù)內(nèi)容都是靜態(tài)的,并且HTTP 1.0只是一種傳送文件的方式。但在不久后web服務(wù)器提供了CGI功能。這意味著我們可以為每個(gè)web請(qǐng)求啟動(dòng)一個(gè)進(jìn)程來(lái)產(chǎn)生動(dòng)態(tài)內(nèi)容。現(xiàn)在,HTTP協(xié)議已經(jīng)很成熟了并且web服務(wù)器變得更加復(fù)雜,擁有了像緩存、安全和session管理這些附加功能。隨著技術(shù)的進(jìn)一步成熟,我們從Kiva和NetDynamics學(xué)會(huì)了公司專屬的基于Java的服務(wù)器端技術(shù)。這些技術(shù)最終全都融入到我們今天依然在大多數(shù)應(yīng)用開(kāi)發(fā)里使用的JSP中。
以上是關(guān)于web服務(wù)器的。現(xiàn)在我們來(lái)討論應(yīng)用服務(wù)器。
在同一時(shí)期,應(yīng)用服務(wù)器已經(jīng)存在并發(fā)展很長(zhǎng)一段時(shí)間了。一些公司為Unix開(kāi)發(fā)了Tuxedo(面向事務(wù)的中間件)、TopEnd、Encina等產(chǎn)品,這些產(chǎn)品都是從類似IMS和CICS的主機(jī)應(yīng)用管理和監(jiān)控環(huán)境衍生而來(lái)的。大部分的這些產(chǎn)品都指定了“封閉的”產(chǎn)品專用通信協(xié)議來(lái)互連胖客戶機(jī)(“fat” client)和服務(wù)器。在90年代,這些傳統(tǒng)的應(yīng)用服務(wù)器產(chǎn)品開(kāi)始嵌入HTTP通信功能,剛開(kāi)始要利用網(wǎng)關(guān)來(lái)實(shí)現(xiàn)。不久后它們之間的界線開(kāi)始變得模糊了。
同時(shí),web服務(wù)器越來(lái)越成熟,可以處理更高的負(fù)載、更多的并發(fā)和擁有更好的特性;應(yīng)用服務(wù)器開(kāi)始添加越來(lái)越多的基于HTTP的通信功能。所有的這些導(dǎo)致了web服務(wù)器與應(yīng)用服務(wù)器的界線變得更窄了。
目前,“應(yīng)用服務(wù)器”和“web服務(wù)器”之間的界線已經(jīng)變得模糊不清了。但是人們還把這兩個(gè)術(shù)語(yǔ)區(qū)分開(kāi)來(lái),作為強(qiáng)調(diào)使用。
當(dāng)有人說(shuō)到“web服務(wù)器”時(shí),你通常要把它認(rèn)為是以HTTP為核心、web UI為向?qū)У膽?yīng)用。當(dāng)有人說(shuō)到“應(yīng)用服務(wù)器”時(shí),你可能想到“高負(fù)載、企業(yè)級(jí)特性、事務(wù)和隊(duì)列、多通道通信(HTTP和更多的協(xié)議)”。但現(xiàn)在提供這些需求的基本上都是同一個(gè)產(chǎn)品。
以上就是關(guān)于web服務(wù)器和應(yīng)用服務(wù)器的全部?jī)?nèi)容。現(xiàn)在我們來(lái)看看第三個(gè)術(shù)語(yǔ),即web容器。
在Java方面,web容器一般是指Servlet容器。Servlet容器是與Java Servlet交互的web容器的組件。web容器負(fù)責(zé)管理Servlet的生命周期、把URL映射到特定的Servlet、確保URL請(qǐng)求擁有正確的訪問(wèn)權(quán)限和更多類似的服務(wù)。綜合來(lái)看,Servlet容器就是用來(lái)運(yùn)行你的Servlet和維護(hù)它的生命周期的運(yùn)行環(huán)境。
在Java里,Servlet使你能夠編寫(xiě)根據(jù)請(qǐng)求動(dòng)態(tài)生成內(nèi)容的服務(wù)端組件。事實(shí)上,Servlet是一個(gè)在javax.servlet包里定義的接口。它為Servlet的生命周期聲明了三個(gè)基本方法——init()、service()和destroy()。每個(gè)Servlet都要實(shí)現(xiàn)這些方法(在SDK里定義或者用戶定義)并在它們的生命周期的特定時(shí)間由服務(wù)器來(lái)調(diào)用這些方法。
類加載器通過(guò)懶加載(lazy-loading)或者預(yù)加載(eager loading)自動(dòng)地把Servlet類加載到容器里。每個(gè)請(qǐng)求都擁有自己的線程,而一個(gè)Servlet對(duì)象可以同時(shí)為多個(gè)線程服務(wù)。當(dāng)Servlet對(duì)象不再被使用時(shí),它就會(huì)被JVM當(dāng)做垃圾回收掉。
當(dāng)Servlet容器啟動(dòng)時(shí),它會(huì)部署并加載所有的web應(yīng)用。當(dāng)web應(yīng)用被加載時(shí),Servlet容器會(huì)一次性為每個(gè)應(yīng)用創(chuàng)建Servlet上下文(ServletContext)并把它保存在內(nèi)存里。Servlet容器會(huì)處理web應(yīng)用的web.xml文件,并且一次性創(chuàng)建在web.xml里定義的Servlet、Filter和Listener,同樣也會(huì)把它們保存在內(nèi)存里。當(dāng)Servlet容器關(guān)閉時(shí),它會(huì)卸載所有的web應(yīng)用和ServletContext,所有的Servlet、Filter和Listner實(shí)例都會(huì)被銷毀。
從Java文檔可知,ServletContext定義了一組方法,Servlet使用這些方法來(lái)與它的Servlet容器進(jìn)行通信。例如,用來(lái)獲取文件的MIME類型、轉(zhuǎn)發(fā)請(qǐng)求或者編寫(xiě)日志文件。在web應(yīng)用的部署文件(deployment descriptor)標(biāo)明“分布式”的情況下,web應(yīng)用的每一個(gè)虛擬機(jī)都擁有一個(gè)上下文實(shí)例。在這種情況下,不能把Servlet上下文當(dāng)做共享全局信息的變量(因?yàn)樗男畔⒁呀?jīng)不具有全局性了)。可以使用外部資源來(lái)代替,比如數(shù)據(jù)庫(kù)。
ServletRequest和ServletResponse從哪里進(jìn)入生命周期?
Servlet容器包含在web服務(wù)器中,web服務(wù)器監(jiān)聽(tīng)來(lái)自特定端口的HTTP請(qǐng)求,這個(gè)端口通常是80。當(dāng)客戶端(使用web瀏覽器的用戶)發(fā)送一個(gè)HTTP請(qǐng)求時(shí),Servlet容器會(huì)創(chuàng)建新的HttpServletRequest和HttpServletResponse對(duì)象,并且把它們傳遞給已經(jīng)創(chuàng)建的Filter和URL模式與請(qǐng)求URL匹配的Servlet實(shí)例的方法,所有的這些都使用同一個(gè)線程。
request對(duì)象提供了獲取HTTP請(qǐng)求的所有信息的入口,比如請(qǐng)求頭和請(qǐng)求實(shí)體。response對(duì)象提供了控制和發(fā)送HTTP響應(yīng)的便利方法,比如設(shè)置響應(yīng)頭和響應(yīng)實(shí)體(通常是JSP生成的HTML內(nèi)容)。當(dāng)HTTP響應(yīng)被提交并結(jié)束后,request和response對(duì)象都會(huì)被銷毀。
當(dāng)客戶端第一次訪問(wèn)web應(yīng)用或者第一次使用request.getSession()獲取HttpSession時(shí),Servlet容器會(huì)創(chuàng)建Session,生成一個(gè)long類型的唯一ID(你可以使用session.getId()獲取它)并把它保存在服務(wù)器的內(nèi)存里。Servlet容器同樣會(huì)在HTTP響應(yīng)里設(shè)置一個(gè)Cookie,cookie的名是JSESSIONID并且cookie的值是session的唯一ID。
根據(jù)HTTP cookie規(guī)范(正規(guī)的web瀏覽器和web服務(wù)器必須遵守的約定),在cookie的有效期間,客戶端(web瀏覽器)之后的請(qǐng)求都要把這個(gè)cookie返回給服務(wù)器。Servlet容器會(huì)利用帶有名為JSESSIONID的cookie檢測(cè)每一個(gè)到來(lái)的HTTP請(qǐng)求頭,并使用cookie的值從服務(wù)器內(nèi)容里獲取相關(guān)的HttpSession。
HttpSession會(huì)一直存活著,除非超過(guò)一段時(shí)間沒(méi)使用。你可以在web.xml里設(shè)定這個(gè)時(shí)間段,默認(rèn)時(shí)間段是30分鐘。因此,如果客戶端已經(jīng)超過(guò)30分鐘沒(méi)有訪問(wèn)web應(yīng)用的話,Servlet容器就會(huì)銷毀Session。之后的每一個(gè)請(qǐng)求,即使帶有特定的cookie,都再也不會(huì)訪問(wèn)到同一個(gè)Session了。servletcontainer會(huì)創(chuàng)建一個(gè)新的Session。
另外,在客戶端的session cookie擁有一個(gè)默認(rèn)的存活時(shí)間,這個(gè)時(shí)間與瀏覽器的運(yùn)行時(shí)間相同。因此,當(dāng)用戶關(guān)閉瀏覽器后(所有的標(biāo)簽或者窗口),客戶端的Session就會(huì)被銷毀。重新打開(kāi)瀏覽器后,與之前的Session關(guān)聯(lián)的cookie就再也不會(huì)被發(fā)送出去了。再次使用request.getSession()會(huì)返回一個(gè)全新的HttpSession并且使用一個(gè)全新的session ID來(lái)設(shè)置cookie。
你現(xiàn)在應(yīng)該已經(jīng)知道所有的請(qǐng)求都在共享Servlet和Filter。這是Java的一個(gè)很棒的特性,它是多線程的并且不同的線程(即HTTP請(qǐng)求)可以使用同一個(gè)實(shí)例。否則,對(duì)每一個(gè)請(qǐng)求都重新創(chuàng)建一個(gè)實(shí)體會(huì)耗費(fèi)很多的資源。
你同樣要知道,你不應(yīng)該使用Servlet或者Filter的實(shí)例變量來(lái)存放任何的請(qǐng)求或者會(huì)話范圍內(nèi)的數(shù)據(jù)。這些數(shù)據(jù)會(huì)被其他Session的所有請(qǐng)求共享。這是非線程安全的!下面的例子說(shuō)明了這個(gè)問(wèn)題:
public class MyServlet extends HttpServlet { private Object thisIsNOTThreadSafe; //Don't to this protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Object thisIsThreadSafe; thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests! thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe. } }
不要這樣做,這會(huì)導(dǎo)致軟件出bug。
本文轉(zhuǎn)載自 ImportNew
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn