Web服務器工做原理概述


不少時候咱們都想知道,web容器或web服務器(好比Tomcat或者jboss)是怎樣工做的?它們是怎樣處理來自全世界的http請求的?它們在幕後作了什麼動做?Java Servlet API(例如ServletContext,ServletRequest,ServletResponse和Session這些類)在其中扮演了什麼角色?這些都是web應用開發者或者想成爲web應用開發者的人必需要知道的重要問  或概念。在這篇文章裏,我將會盡可能給出以上某些問  的答案。請集中精神! html

文章章節: java

· 什麼是web服務器、應用服務器和web容器? web

· 什麼是Servlet?他們有什麼做用? 數據庫

· 什麼是ServletContext?它由誰建立? 瀏覽器

· ServletRequest和ServletResponse從哪裏進入生命週期? 緩存

· 如何管理Session?知道cookie嗎? 安全

· 如何確保線程安全? 服務器

什麼是web服務器,應用服務器和web容器? cookie

我先討論web服務器和應用服務器。讓我在用一句話大概講講: session

「在過去它們是有區別的,可是這兩個不一樣的分類慢慢地合併了,而現在在大多在狀況下和使用中能夠把它們當作一個總體。」

Mosaic瀏覽器(一般被認爲是第一個圖形化的web瀏覽器)和超連接內容的初期,演變出了「web服務器」的新概念,它經過HTTP協議來提供靜態頁面內容和圖片服務。在那個時候,大多數內容都是靜態的,而且HTTP 1.0只是一種傳送文件的方式。但在不久後web服務器提供了CGI功能。這意味着咱們能夠爲每一個web請求啓動一個進程來產生動態內容。如今,HTTP協議已經很成熟了而且web服務器變得更加複雜,擁有了像緩存、安全和session管理這些附加功能。隨着技術的進一步成熟,咱們從Kiva和NetDynamics學會了公司專屬的基於Java的服務器端技術。這些技術最終全都融入到咱們今天依然在大多數應用開發裏使用的JSP中。


以上是關於web服務器的。如今咱們來討論應用服務器。

在同一時期,應用服務器已經存在並發展很長一段時間了。一些公司爲Unix開發了Tuxedo(面向事務的中間件)、TopEnd、Encina等產品,這些產品都是從相似IMS和CICS的主機應用管理和監控環境衍生而來的。大部分的這些產品都指定了「封閉的」產品專用通訊協議來互連胖客戶機(「fat」 client)和服務器。在90年代,這些傳統的應用服務器產品開始嵌入HTTP通訊功能,剛開始要利用網關來實現。不久後它們之間的界線開始變得模糊了。

同時,web服務器愈來愈成熟,能夠處理更高的負載、更多的併發和擁有更好的特性;應用服務器開始添加愈來愈多的基於HTTP的通訊功能。全部的這些致使了web服務器與應用服務器的界線變得更窄了。

目前,「應用服務器」和「web服務器」之間的界線已經變得模糊不清了。可是人們還把這兩個術語區分開來,做爲強調使用。

當有人說到「web服務器」時,你一般要把它認爲是以HTTP爲核心、web UI爲嚮導的應用。當有人說到「應用服務器」時,你可能想到「高負載、企業級特性、事務和隊列、多通道通訊(HTTP和更多的協議)」。但如今提供這些需求的基本上都是同一個產品。

以上就是關於web服務器和應用服務器的所有內容。如今咱們來看看第三個術語,即web容器。


在Java方面,web容器通常是指Servlet容器。Servlet容器是與Java Servlet交互的web容器的組件。web容器負責管理Servlet的生命週期、把URL映射到特定的Servlet、確保URL請求擁有正確的訪問權限和更多相似的服務。綜合來看,Servlet容器就是用來運行你的Servlet和維護它的生命週期的運行環境。

什麼是Servlet?他們有什麼做用?

在Java裏,Servlet使你可以編寫根據請求動態生成內容的服務端組件。事實上,Servlet是一個在javax.servlet包裏定義的接口。它爲Servlet的生命週期聲明瞭三個基本方法——init()、service()和destroy()。每一個Servlet都要實現這些方法(在SDK裏定義或者用戶定義)並在它們的生命週期的特定時間由服務器來調用這些方法。

類加載器經過懶加載(lazy-loading)或者預加載(eager loading)自動地把Servlet類加載到容器裏。每一個請求都擁有本身的線程,而一個Servlet對象能夠同時爲多個線程服務。當Servlet對象再也不被使用時,它就會被JVM當作垃圾回收掉。

懶加載的Servlet


預加載的Servlet


什麼是ServletContext?它由誰建立?

當Servlet容器啓動時,它會部署並加載全部的web應用。當web應用被加載時,Servlet容器會一次性爲每一個應用建立Servlet上下文(ServletContext)並把它保存在內存裏。Servlet容器會處理web應用的web.xml文件,而且一次性建立在web.xml裏定義的Servlet、Filter和Listener,一樣也會把它們保存在內存裏。當Servlet容器關閉時,它會卸載全部的web應用和ServletContext,全部的Servlet、Filter和Listner實例都會被銷燬。

從Java文檔可知,ServletContext定義了一組方法,Servlet使用這些方法來與它的Servlet容器進行通訊。例如,用來獲取文件的MIME類型、轉發請求或者編寫日誌文件。在web應用的部署文件(deployment descriptor)標明「分佈式」的狀況下,web應用的每個虛擬機都擁有一個上下文實例。在這種狀況下,不能把Servlet上下文當作共享全局信息的變量(由於它的信息已經不具備全局性了)。可使用外部資源來代替,好比數據庫。

ServletRequest和ServletResponse從哪裏進入生命週期?

Servlet容器包含在web服務器中,web服務器監聽來自特定端口的HTTP請求,這個端口一般是80。當客戶端(使用web瀏覽器的用戶)發送一個HTTP請求時,Servlet容器會建立新的HttpServletRequest和HttpServletResponse對象,而且把它們傳遞給已經建立的Filter和URL模式與請求URL匹配的Servlet實例的方法,全部的這些都使用同一個線程。

request對象提供了獲取HTTP請求的全部信息的入口,好比請求頭和請求實體。response對象提供了控制和發送HTTP響應的便利方法,好比設置響應頭和響應實體(一般是JSP生成的HTML內容)。當HTTP響應被提交併結束後,request和response對象都會被銷燬。

如何管理Session?知道cookie嗎?

當客戶端第一次訪問web應用或者第一次使用request.getSession()獲取HttpSession時,Servlet容器會建立Session,生成一個long類型的惟一ID(你可使用session.getId()獲取它)並把它保存在服務器的內存裏。Servlet容器一樣會在HTTP響應裏設置一個Cookie,cookie的名是JSESSIONID而且cookie的值是session的惟一ID。

根據HTTP cookie規範(正規的web瀏覽器和web服務器必須遵照的約定),在cookie的有效期間,客戶端(web瀏覽器)以後的請求都要把這個cookie返回給服務器。Servlet容器會利用帶有名爲JSESSIONID的cookie檢測每個到來的HTTP請求頭,並使用cookie的值從服務器內容裏獲取相關的HttpSession。

HttpSession會一直存活着,除非超過一段時間沒使用。你能夠在web.xml裏設定這個時間段,默認時間段是30分鐘。所以,若是客戶端已經超過30分鐘沒有訪問web應用的話,Servlet容器就會銷燬Session。以後的每個請求,即便帶有特定的cookie,都不再會訪問到同一個Session了。servletcontainer會建立一個新的Session。

現有的Session


新的Session


另外,在客戶端的session cookie擁有一個默認的存活時間,這個時間與瀏覽器的運行時間相同。所以,當用戶關閉瀏覽器後(全部的標籤或者窗口),客戶端的Session就會被銷燬。從新打開瀏覽器後,與以前的Session關聯的cookie就不再會被髮送出去了。再次使用request.getSession()會返回一個全新的HttpSession而且使用一個全新的session ID來設置cookie。

如何確保線程安全?

你如今應該已經知道全部的請求都在共享Servlet和Filter。這是Java的一個很棒的特性,它是多線程的而且不一樣的線程(即HTTP請求)可使用同一個實例。不然,對每個請求都從新建立一個實體會耗費不少的資源。


你一樣要知道,你不該該使用Servlet或者Filter的實例變量來存聽任何的請求或者會話範圍內的數據。這些數據會被其餘Session的全部請求共享。這是非線程安全的!下面的例子說明了這個問  :

1

2

3

4

5

6

7

8

9

10

11

12

publicclassMyServletextendsHttpServlet

{

    privateObject thisIsNOTThreadSafe;//Don't to this

 

    protectedvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException

    {

        Object thisIsThreadSafe;

 

        thisIsNOTThreadSafe = request.getParameter("foo");// BAD!! Shared among all requests!

        thisIsThreadSafe = request.getParameter("foo");// OK, this is thread safe.

    }

}

不要這樣作,這會致使軟件出bug。

相關文章
相關標籤/搜索