servlet v2.3規範學習筆記(更新到第十二章)

來源:http://www.blogjava.net/CrazyJava/articles/183076.html

Java Servlet Specification  Version 2.3 第一章 概要 1.1 什麼是servlet         servlet是一種基於web組件的java技術,由容器管理,產生動態內容。象其他基於java的組件一樣,servlet是不依賴平臺的的java類,被編譯爲中間字節碼,可被動態裝載運行於支持java的web服務器上。這裏說的容器,有時也稱它爲servlet引擎,提供Servlet功能的web服務器擴展,servelt通過一種由servlet容器實現的request/response範式(paradigm)與web客戶機交互。 1.2什麼是servlet容器         servlet容器是web服務器或應用服務器的一部分,它們提供處理處理request併發送response的網絡服務,解析基於MIME的request,準備基於MIME的response。servlet容器包含並管理着servlet對象的一生。         servlet容器可以被嵌入web服務器主機,或者通過服務器本地擴展API安裝爲web服務器的一個組件。同時,它也可以被嵌入到支持web功能的應用服務器中。         所有的servlet容器必須支持以HTTP作爲request和response的協議,但額外的協議如HTTPS可以支持。應支持的HTTP最低版本爲HTTP/1.0,強烈議也支持HTTP1.1規範。         servlet容器可以在其執行環境中放置安全制約。Java2平臺,標準1.2或者J2EE1.3環境,應當使用由java2平臺定義的許可架構下的約束。例如,高端應用服務器可以限制線程對象的創建,確保容器內的其他組件免收影響。J2SE1.2是構建servlet容器的最低版本。          1.3 例子 以下是一系列典型的場景序列:         1.客戶機(即,瀏覽器)訪問web服務器,併發送HTTP請求。         2.web服務器接收到了這個請求,並向下傳遞給了servlet容器。servlet容器可以與web服務器運行在同一進程裏,也可以在同一主機上的不同進程裏,或者運行於不同主機上。         3.servlet容器使用servlet配置信息而決定調用哪一個servlet,同時向其傳遞request和response對象參數。         4.servlet利用request對象得到遠端用戶信息,HTTP POST參數是什麼,以及其他相關數據。servlet執行其編碼邏輯,併產生數據,通過response對象送回客戶機。         5.一旦servlet完成處理request,容器應確保response對象被flush,並將控制權返回web服務器。 1.4 和其他技術的比較         功能上,servlet居於CGI和服務器擴展(如Netscape Server API或 Apache modules)之間。         但servlet還具有一些其他服務器擴展技術沒有的先進性:         .它們通常比CGI腳本運行快。         .它們使用很多web服務器都支持的標準API。         .它們具有所有java編程語言具有的優點,包括開發簡單平臺獨立等。         .它們可以訪問java平臺大量的API。 1.5與J2EE的關係         Servlet API v2.3 是JavaTM 2 平臺, 企業版 v1.31的必需的API 。servlet容器和發佈servlet必須滿足其他的需求在J2EE規範中都有描述。 第二章 Servlet接口         servlet接口是servlet主要抽象的API。所有servlet都需要直接實現這一接口或者繼承實現了該接口的類。servlet API中有兩個類實現了Servlet接口,GenericServlet和HttpServlet。大多數情況下,開發人員只需要在這兩個類的基礎上擴展來實現他們自己的Servlet。 2.1 request處理方法         servlet接口定義了service方法來處理客戶機的請求。當容器將每個請求傳遞給servlet實例處理時都會調用該方法。爲應付同時到達的請求,通常要求web開發人員編寫的service方法可以多線程執行。         開發人員在不同線程內併發執行service方法來處理同時到達同一servlet的多個請求。 2.1.1 HTTP規範request處理方法         HttpServlet,實現了Servlet接口的抽象類,添加了一些附加的方法處理HTTP請求,由service方法自動調用。這些方法是:         .doGet處理HTTP GET request         .doPost處理HTTP POST request         .doPut處理HTTP PUT request         .doDelete處理HTTP DELETE request         .doHead處理HTTP HEAD request         .doOption處理HTTP OPTION request         .doTrace處理HTTP TRACE request                  在開發HTTP Servlet的時候,開發人員一般關注doGet和doPost方法.其他方法在HTTP開發時很少用. 2.1.2 附加方法         doGet和doPost方法允許開發人員支持HTTP1.1特性.doHead()方法實際是一種特殊的doGet方法,它只返回由doGet產生的頭信息.doOption 方法返回servlet支持的所有HTTP方法的信息.doTrace方法產生的響應包含TRACE請求發送的所有頭實例.         對於僅支持HTTP/1.0的容器,只需支持doGet,doPost,doHead方法.因爲HTTP/1.0沒有定義PUT,DELETE,OPTIONS,TRACE方法. 2.1.3 條件Get支持         HttpServlet接口定義了getLastModified方法,目的是支持有條件的GET操作.一個有條件的GET操作所請求的資源只有在指定時間內被修改了的情況下才需要發送.在某些情形下,實現該方法可以更加有效地利用網絡資源. 2.2 實例的數量         servlet聲明包含在web應用配置描述內,控制着容器如何提供servlet實例。因爲servlet不運行於分佈式環境(缺省),容器爲每個Servlet聲明維護一個實例.然而,當servlet實現SingleThreadModel接口時,容器可以持有多個servlet實例來應付繁重的請求,但要保證一個實例每次只處理一個請求.         當servlet被髮布到分佈式應用時,容器可以在每個虛擬機中爲每個servlet聲明持有一個實例.如果實現SingleThreadModel,可以在每個虛擬機中爲每個聲明持有多個servlet實例. 2.2.1 注意單線程模式         SingleThreadModel只允許某一時刻只能有一個線程執行指定的servlet實例的service方法.應該注意到,此保證只針對servlet實例而言,因爲容器可以選擇池化這些對象.多個servlet實例可以同時訪問的對象,例如HttpSession對象,在任意時候對多個servlet都是可用的,哪怕這些servlet實現了singleThreadModel. 2.3 servlet生命週期         servlet的生命週期定義了裝載,實例化,初始化,處理客戶機請求,卸載等等。用API表示生命週期就是init,service,和destroy方法. 2.3.1 裝載和實例化         容器負責servlet的裝載和實例化.它們可以發生在容器啓動時,也可以延遲到容器認爲需要該servlet處理request時.         當容器啓動時,容器必須可以定位所需要的servlet類,並使用Java類裝載機構裝載servlet類.從本地文件系統中,或從遠程文件系統中或者從其他網絡服務中都可以裝載servlet類.         裝載完成後,容器實例化該類.         servlet對象被實例化後,容器必須在使用它處理客戶機的請求之前初始化這個servlet實例.初始化的意義是srvlet對象可以讀取一些持久性的配置數據,或者初始化某些重量級型資源(比如JDBC連接),或是執行某些一次性的行爲.容器使用init方法並傳遞一個單例SrvletConf ig對象參數(每個servlet聲明只有一個).該配置對象允許servlet訪問應用配置信息中的初始化參數,同時提供了一個實現了ServletContext接口的對象來訪問servlet運行環境的信息. 2.3.2.1 初始化的錯誤條件         在初始化期間,servlet實例可以拋出UnavailabelException或者ServletException異常.發生異常時不能將servlet放進可用服務中,容器必須釋放它,因爲未被成功初始化,所以無需調用destroy方法.         初始化失敗後,應重新創建一個新的實例並初始化它.規則是,當UnavailabelException指示了最小不可用時間,容器必須等待這個最小時間才創建並初始化新的實例. 2.3.2.2 Tool Considerations         工具裝載並內省web應用而觸發類的靜態初始化方法有別於調用servlet的init方法.在沒有調用init方法前,開發人員不應假定sevlet是在一個活躍的servlet容器運行環境中。也就是說,servlet不應在靜態初始化方法裏試圖建立數據庫連接等. 2.3.3處理請求         當servlet被正確初始化後,容器就可以用它處理客戶機的請求了.請求用ServletRequest類型的對象表示,servlet通過調用ServletResponse的對象上的方法填充該請求的響應。這些對象由service方法作爲參數傳遞進來.         在HTTP請求中,容器提供的這些對象類型爲HttpServletRequest和HttpServletResponse.         一個被容器放進服務序列的servlet實例也有可能在整個生命週期中都不處理請求. 2.3.3.1多線程         servlet容器可以向servlet的service方法發送併發請求.爲了處理這些請求,開發人員必須在他們的service方法中遵守有關的多線程併發處理規則.         否則,一個可替代的辦法是實現SingleThreadModel接口,它需要容器保證在service方法一次只有處理一個請求.容器通過序列化一個servlet上的請求來滿足這個需求,還可以通過持有一個servlet實例池的方式.若servlet屬於分佈式應用的一部分,容器可以在應用分佈的每個虛擬機上持有一個servlet實例池.         若servlet沒有實現SingleThreadModel,而是使用synchronized關鍵字定義了service方法(或doGet,doPost),容器就不會使用實例池,但必須序列式地處理到達此servlet的請求,強烈建議開發人員不要同步service方法,否則會嚴重影響性能.          2.3.3.2 處理請求期間的異常         servlet在處理request期間可以拋出ServletException或UnavailableException異常. ServletException表明在處理request時發生了一些錯誤,此時容器應使用適當的方式清除此請求.         UnavailableException顯示該servlet不能處理請求,有可能是暫時的,也有可能是永久性的.         如果是永久性的不可用,容器必須從服務中移除該servlet實例,並調用它的destroy()方法,然後釋放實例.         如果是暫時性的不可用,容器可以在不可用期間不發送任何請求到該servlet處理.         在此期間被容器拒絕的請求,必須以SERVICE_UNAVAILABLE (503)狀態碼返回,同時在HTTP響應頭Retry-After中指明何時服務可用.         容器也可以選擇忽略這兩種可用性的區別,將所有UnavailableExceptions當作永久性的,而直接移除該servlet實例. 2.3.3.3 線程安全         request和response對象不是線程安全的,這意味着它們應該只能在處理該請求南叱棠誆渴褂?         在其他線程中使用被引用的request和response對象將引起不可預期的後果. 2.3.4 終止服務         容器並不需要永久持有servlet. servlet實例在容器中可能只存在數毫秒,也可能在整個容器的生命週期中都存在(可能是幾天,個月,幾年)         當容器決定應該從服務中移除servlet時,它調用servlet接口上的destroy()方法,這樣,servlet可以釋放它所使用的資源,或者存儲任何持久性的狀態.         在容器調用的destroy()方法之前.必須允許正在運行service方法的線程完成執行,或者延遲運行一段服務器定義的時限.         一旦servlet實例的destroy()方法開始被調用,容器不用再發送其他請求到該servlet實例處理.即使容器需要重新激活該servlet,它也必須重新創建一個實例。         當destroy()方法調用完成後,容器必須釋放該實例,以便它可以被垃圾收集. 第三章 Servlet Context 3.1 介紹ServletContext接口         ServletContext接口定義了web應用的servlet視圖.容器提供者有責任提供對ServletContext接口的實現.通過ServletContext對象,servlet可以記錄日誌,獲得資源的URL引用,存儲其他servlet也可以訪問的屬性.         ServletContext以Web服務器中一條已知的路徑爲根,例如,servlet context可以位於http://www.mycorp.com/catalog,所有以/catalog開始的請求被髮送到與此ServletContext相關聯的web應用. 3.2 ServletContext接口的範圍         每個應用都會有一個ServletContext對象與之關聯,當容器分佈在在多個虛擬機上時,web應用在所分佈的每個虛擬機上都擁有一個ServletContext實例.缺省情況下,ServletContext不是分佈式的,並且只存在於一個虛擬機上。          3.3 初始化參數         以下ServletContext接口中的方法允許servlet訪問開發人員在配置描述中定義的web應用初始化參數:         . getInitParameter         . getInitParameterNames         應用開發人員使用初始化參數傳遞構建信息,例如管理員的郵件地址等.          3.4 context屬性         可以在context中用名稱邦定一個對象屬性.context中的任何屬性對於同一web應用下的其他servlet都是可用的.下列方法完成了這樣的功能:         . setAttribute         . getAttribute         . getAttributeNames         . removeAttribute 3.4.1 在分佈式容器中的context屬性         對於創建它們的虛擬機來說context屬性是本地的. 這使得ServletContext屬性不能以共享內存的方式存儲在分佈式的容器中.如果有些信息需要在不同的機器上運行的servlet之間共享的話,它們應該被存儲在session中,數據庫中,或EJB組件中. 3.5 資源         使用ServletContext接口可以直接訪問web應用中的靜態內容文檔結構.包括HTML,GIF和JPEG文件.如以下方法:         .getResource         .getResourceAsStream         這兩個方法的參數都是以"/"開頭的字符串,表示資源相對於context根的相對路徑.文檔結構可以存在於服務器文件系統,或是war包中,或是在遠程服務器上,抑或其他位置.         以上方法不可以用來獲得動態資源,比如,getResource("/index.jsp"),這個方法將返回該jsp文件的源碼,而不是動態頁面.可以用"Dispatching Requests"獲得動態內容.         列出web應用中可被訪問的資源,可以使用getResourcePaths(String path)方法。          3.6多主機和servlet context         web服務器支持在一臺機器上共享一個IP的多個邏輯主機,這種能力被稱爲"虛擬主機",每個邏輯主機都擁有它自己的servlet context。servlet context不能跨虛擬主機共享. 3.7 重新裝載          雖然容器提供重新裝載的實現對於開發有益,但不是必須的。這些實現必須確保所有的servlet、和它們所使用的類在單獨的類裝載器範圍內被裝載。此機制保證了應用正常運行。          Previous generations of containers created new class loaders to load a servlet,distinct from class loaders used to load other servlets or classes used in the servlet context. This could cause object references within a servlet context to point at unexpected classes or objects, and cause unexpected behavior. The requirement is needed to prevent problems caused by demand generation of new class loaders.          (不確定的參考譯文:          容器用來裝載servlet的類裝載器和ServletContext用來裝載servlet和其他類的裝載器不同,這導致在servlet上下文之內的對象引用指向不可預期的類或對象, 和不可預期的行爲。需要防止由新的類裝載器產生的問題.) 3.8 臨時工作目錄         每個servlet context都有它自己的臨時存儲目錄,容器必須爲每個servlet conetxt提供一個私有的臨時目錄,存儲於context屬性javax.servlet.context.tempdir.該對象必須是java.io.File類型.容器啓動時,不需要維護該臨時目錄的內容,但必須確保一個servlet context臨時目錄的內容對其他web應用(servlet context)是不可見的. 第四章 Request 4.1 HTTP協議參數         servlet的請求參數是客戶機發送給servlet容器的字符串,它是請求的一部分.當請求是一個HttpServletRequest對象時,且條件設置合適時,容器從URI請求字符串和POST數據中組裝參數.         參數的存儲爲名稱-值成對形式,對於同一個名稱可能存在多參數值.以下ServletRequest接口方法可以訪問參數:         .getParameter         .getParameterNames         .getParameterValues         getParameterValues方法返回一個字符串對象數組,包含有和指定名稱關聯的所有參數值.getParameter方法返回的是該數組的第一個參數值.         查詢字符串和post body 包含的數據被組裝到request參數集合中,query string中的數據順序要優先於post body中的數據.比如: 如果一個請求使用查詢字符串 a=hello 和post body a=goodbye&a=world,最後的參數集順序是a=(hello,goodbye,world).         路徑參數需要使用getRequestURI和getPathInfo方法獲得. 4.1.1 什麼時候參數可用         POST form 中的數據被放進參數集之前,必須符合以下條件:         1.必須是HTTP或HTTPS請求         2.HTTP方法是POST         3.內容類型是application/x-www-form-urlencoded         4.servlet 調用了request對象上的getParameter之類與參數相關的方法.         如上述條件不滿足的話,被POST的form中的數據不會包含在參數集中,但數據仍可以通過request對象的輸入流得到。否則數據不能通過request對象的輸入流得到。 4.2 屬性         屬性是和request關聯的對象。它一般被容器用作存儲不能通過API獲得的信息,或者是用作與其他servlet的通訊信息(通過RequestDispatcher)。屬性可以用以下方法訪問:         .getAttribute         .getAttributeNames         .setAttribute         一個屬性名只能和一個屬性值關聯。         以“java.”,"javax."開始的屬性名是本規範的保留定義,同樣,以"sun.","com.sun."開頭的屬性名是Sun公司的保留定義。建議所有的屬性名以包命名規範。 4.3 頭(Headers)         servlet通過以下方法訪問HTTP request的頭信息。         .getHeader         .getHeaders         .getHeaderNames         .getHeader方法返回與頭名稱對應的頭信息。同一個名稱可能有多個頭信息對應。比如:Cache-Control頭。如果這樣,該方法應該                返回第一個。要取得所有信息,則使用getHeaders方法。         頭信息也許是某些整型或日期型,可以直接使用下面方法讀取:         .getIntHeader         .getDateHeader         如果getIntHeader方法不能將值轉換爲整數,將拋出NumberFormatException異常。如果.getDateHeader方法不能將值轉換爲日期對象,將拋出IllegalArgumentException異常。 4.4 請求路徑         請求路徑由許多重要的部分組成。下列元素從請求URI獲得,並通過request對象暴露。         .Context Path:和此servlet所在的ServletContext關聯的路徑前綴,如果context是"default" context,那麼該路徑爲"",另外,如果該context不是root,那麼路徑以"/"開頭,但不能以"/"結束。         .servlet path:此部分和請求的映射相關,以"/"開始,但如果該映射是"/*",那麼servlet路徑此時爲""         .PathInfo:此部分是context path 和servlet path 的一部分。如沒有額外路徑它爲null,否則是以"/"開始的字符串。         HttpServletRequest接口中的以下方法可以訪問這些信息:         .getContextPath         .getServletPath         .getPathInfo                  值得注意的是,URI和路徑之間除了URL編碼區別外,以下等式是成立的:         requestURI = contextPath + servletPath + pathInfo         例子:         Context Path         /catalog         Servlet Mapping         Pattern: /lawn/*                         Servlet: LawnServlet         Servlet Mapping         Pattern: /garden/*                         Servlet: GardenServlet         Servlet Mapping         Pattern: *.jsp                         Servlet: JSPServlet         我們發現:         Request Path                         Path Elements         /catalog/lawn/index.html                 ContextPath: /catalog                                         ServletPath: /lawn                                         PathInfo: /index.html         /catalog/garden/implements/                 ContextPath: /catalog                                         ServletPath: /garden                                         PathInfo: /implements/         /catalog/help/feedback.jsp                 ContextPath: /catalog                                         ServletPath: /help/feedback.jsp                                         PathInfo: null 4.5 路徑轉換方法         API中有兩個方便的方法可以讓開發人員獲得和某個路徑相關的文件系統路徑:         .ServletContext.getRealPath         .HttpServletRequest.getPathTranslated         getRealPath接受一個字符串參數,並返回和該路徑相關聯的文件系統路徑。getPathTranslated方法則可以得到該request的PathInfo對應的真實路徑。下列情況下,servlet容器不能判別合法的文件路徑,如,web應用以war包形式運行,或者不是本地文件路徑,或者在數據庫中,這些方法將返回NULL. 4.6 cookie         HttpServletRequest接口提供getCookies方法獲得該request中的cookies數組。這些cookies是客戶機每次發送給服務器請求中的數據,其形式爲cookie名和cookie值。當cookie被送回給客戶機時也可設置其他屬性,比如註釋,但一般是不會送回服務器的。 4.7 SSL屬性         如果請求是通過安全協議傳輸的,如:HTTPS,那麼ServletRequest接口的isScure方法可以得到。 4.8 國際化         客戶機可以向web服務器提示它以何種語言接受服務器的響應.HTTP1.1規範中指出在頭信息Accept-Language表示。以下方法可以得到發送者的地域信息:         .getLocale         .getLocales         如果客戶機沒有指定地域信息,servlet容器將會使用默認的地域信息設定。 4.9 請求數據編碼         目前,許多瀏覽器在Content-Type頭中不會指定字符編碼方式,那麼容器就會使用"ISO-8859-1"方式解析POST數據,而此時,爲了向開發人員提示字符編碼方式未指定,容器將會在getCharacterEncoding返回null.         如果客戶機沒有設置字符編碼信息,但是request數據又以和缺省編碼方式不同的方式編碼,就會發生數據破壞。setCharacterEncoding(String enc)方法可以防止這種狀況發生,但是必須在解析數據或從request中讀取數據之前調用。否則調用該方法不會有任何效果。 4.10 request對象的生命週期         request對象只在servlet的service方法範圍內有效。或者是在filter的doFilter方法內,開發人員必須確信在範圍之外引用request對象行爲不會導致不可預計的後果。 第五章 Response         response對象包裝了所有從服務器發送到客戶機的的信息,在HTTP協議中,這些信息被分爲HTTP頭和消息體的兩部分。          5.1 緩衝         servlet容器被允許但不被要求,緩衝發送到客戶機的輸出.一般情況下容器都會做緩衝,並且允許servlet定製緩衝參數。下列方法和緩衝相關。         .getBufferSize         .setBufferSize         .isCommitted         .reset         .resetBuffer         .flushBuffer         這些方法對ServletOutputStream和Writer有效。         getBufferSize返回正在使用的緩衝大小,如果沒有使用緩衝,返回整數0。可以通過setBufferSize設定緩衝大小,緩衝分配的ad校可以與servlet請求的不同,但至少應不比所請求的小。此方法應在調用ServletOutputStream或Writer向客戶機發送數據之前調用。如果有任何數據已經被髮送,此方法將拋出IllegalStateException異常.         isCommitted方法返回一個boolean值顯示是否有任何response字節被髮送回客戶機。flushBuffer強制將buffer中的內容發送給客戶機。reset方法在response還沒有被commit以前將buffer的內容清空,頭信息和狀態碼也被清除。resetBuffer則只清除buffer內容。         如果response已經被commit,調用reset和resetBuffer將拋出IllegalStateException異常,同時response對象不會發生改變。         一旦數據被開始發送給客戶機,response對象就被認爲是committed狀態。 5.2 頭         servlet用下面的方法設置HTTP頭信息。         .setHeader         .addHeader                 setHeader方法會替換已經被設置的值,而addHeader則會添加一個值到同名頭的值集合中。         爲保證成功地將頭信息傳送到客戶機,必須在response對象被提交以前,設置HTTP頭信息。         servlet開發人員有責任確保Content-type頭被正確設置,HTTP1.1規範並不要求HTTP response中設置該頭。當開發人員沒有設置該值,        容器也不要設置缺省值。 5.3 方便的方法         .sendRedirect         .sendError         sendRedirect方法會自動設置合適的頭與內容,引導客戶機跳轉到另一個URL去。 使用相對路徑作爲參數也是合法的,但容器必須將相對路徑轉換爲絕對路徑送回客戶機。如果由於某些原因不能轉換,必須拋出IllegalArgumentException異常.         sendError方法自動設置返回客戶機的頭信息和錯誤信息,一個可選的字符串類型的變量,可用來顯示錯誤信息的內容部分。         這兩個方法對於response的commit都有影響,如response還沒被提交,將終止提交。這些方法後調用的輸出都將被忽略。         若數據被寫進緩衝,但還沒有發送到客戶機,這些數據將被這兩個方法發送的數據代替,如果response已經被提交,將拋出                        IllegalStateException異常. 5.4 國際化         setLocale方法可以設置response對象的語言屬性,此方法必須在開發人員調用getWriter之前使用。         注意。setContentType方法將覆蓋setLocale設定的值。 5.5 response對象的關閉         當response被關閉時,容器必須立即發送所有緩衝中的數據到客戶機,下列情形顯示response對象被關閉了。         .servlet的service方法結束。         .當發送完由setContentLength設定的長度的內容後。         .調用了sendError方法。         .調用了sendRedirect方法。 5.6 response對象的生命週期         每個response對象只在service方法範圍內可用,或者是filter的doFilter方法內。容器通常會回收response對象以避免頻繁創建response對象造成的性能過載。開發人員在可用範圍外引用response對象時,必須確保不會引起不可預知的行爲。 第六章  filter         Filter是規範2.3新提供的特性,它使得請求與響應過程的信息轉換很敏捷。 6.1 什麼是Filter         Filter是一段可重用的,轉換HTTP請求,響應內容和頭信息的代碼。Filter通常不象servlet那樣會創建response或對請求作出響應。它們只是修改對資源的請求或對資源的響應。         Filter對靜態和動態資源都可以起作用。filter的一般作用:         .在request到達它調用的資源之前訪問該資源。         .在request到達它調用的資源之前處理該資源。         .修改request頭和數據,通過重新包裝request對象。         .修改response頭和數據,通過重新包裝response對象。         .攔截監聽資源的調用。         .以一定順序對一個或一組servlet或者靜態資源作用。 6.1.1 Filter的例子         .認證filter         .日誌與審覈filter         .圖像轉換filter         .數據壓縮filter         .加密Filter         .令牌filter         .出發資源訪問事件的filter         .轉換XML文檔的XSLT filter         .MIME-type 鏈filter         .緩存filter 6.2 主要概念         開發人員實現javax.servlet.Filter接口來創建filter,同時提供一個公共無參數的構造函數。該類應該被包含在web應用中。在發佈文件中,以“filter”,"filter-mapping"元素聲明配置。 6.2.1 filter 生命週期         web應用發佈完成之後,在request訪問web資源之前,容器必須定位需要應用到該資源上的filter列表。容器需要確保實例化列表中的每個filter並調用它的init方法。如不能正確執行,filter可以拋出異常。 配置描述文件中每個filter的聲明在每個虛擬機中僅僅只有一個實例。容器提供filter配置祕書中聲明的config對象, 它包含了該web應用的ServletContext引用,和filter初始參數。         當容器接收到request,將取得列表中的第一個filter實例,並調用它的doFilter方法。將傳入ServletRequest,ServletResponse和filterchain的引用。         doFilter方法遵循以下模式:         1.該方法檢測request的頭信息         2.可能會用一個定製的ServletRequest或HttpServletRequest包裝request對象。         3.可能會用一個定製的ServletResponse或HttpServletResponse包裝response對象。         4.filter可以調用filter鏈中的下一個入口,可能是一個filter,也可能是目的web資源。         5.調用鏈中的下一個filter之後,filter可以檢測響應頭信息。         6.處理過程中,filter可能拋出異常。如果在doFilter中拋出UnavailableException,容器不要繼續filter鏈的處理,如飛永久性異        常,它可以選擇在稍晚的時候重新執行整個filter鏈。          6.2.2 包裝request和response         filter的核心概念就是包裝request和response對象,以便於執行filter任務時,覆蓋其行爲。在此模型中,開發人員不僅能夠覆蓋request和response對象上已有的方法,還可以爲某個特定的過濾任務在整個鏈上提供新的API。例如,開發人員可能想在response對象上使用比out流和writer更高級的輸出對象,例如,允許DOM對象寫回客戶機的API。         爲了支持這種類型的filter,容器必須滿足下列需求。當一個filter調用filter chain的doFilter方法時,容器必須確保傳到下一Filter或web資源入口的request和response對象,和調用filter的doFilter方法傳入的是同一個對象。         同樣的,被包裝的request、response對象和傳入的也必須是一致的。 6.2.3 filter環境         配置描述中可以使用一系列參數初始化filter,描述符爲"init-param",filter在運行時可以使用FilterConfig對象上的getInitParameter和getInitParameterNames方法得到參數名和值。FilterConfig也提供對ServletContext的訪問。 6.2.4 在web應用中配置filter         在配置描述中,filter以filter元素定義。         filter-name:用來映射該filter到一個servlet或者URL         filter-class:容器用來識別filter類型         init-params:初始化參數         圖標,文本描述,顯示名稱都是可選項描述,主要給縣骨幹工具軟件使用。對於每個filter聲明,容器必須正確地實例化一個filter對象,如果對於一個filter類定義了多個聲明,容器將會生成多個實例。 例子:         filter聲明:         <filter>                 <filter-name>Image Filter</filter-name>                 <filter-class>com.acme.ImageServlet</filter-class>         </filter>         filter聲明後,應使用filter-mapping元素定義該filter要應用的servlet或是靜態資源。         <filter-mapping>                 <filter-name>Image Filter</filter-name>                 <servlet-name>ImageServlet</servlet-name>         </filter-mapping>         filter也可以使用URL匹配模式和一組servlet或靜態資源關聯起來。         <filter-mapping>                 <filter-name>Logging Filter</filter-name>                 <url-pattern>/*</url-pattern>         </filter-mapping>                  此處,Logging filter被應用到applicationlide所有servlet和靜態資源上了,因爲所有請求URI都匹配"/*"。         當用url-pattern處理filter-mapping時,容器必須用路徑映射規則判斷所請求的URI是否匹url-pattern。         容器針對某個被請求的URI構建的filter鏈的順序爲:         1.首先是url-pattern匹配的filter,如有多個,其順序是配置描述的順序。         2.然後是servlet-name匹配的filter,如有多個,其順序是配置描述的順序。                  以上兩點意味着容器:         .根據匹配規則11.2確定被訪問的目標Web資源         .如果通過servlet名稱匹配到了filter,且web資源擁有servlet名稱,容器按照配置描述的順序構建filter鏈。鏈的底部就是最後一個通過servlet名稱匹配的filter,並且由它調用目的web資源。         .如果有url-pattern匹配的request URI的filter,容器以配置描述中的順序構建url-pattern匹配的filter鏈.鏈的底部是最後一個url-pattern匹配到的filter,並且該filter將調用第一個servlet-name匹配的filter,如沒有則直接調用目的web資源.         若希望提高容器性能,最好緩存filter鏈,以免每次請求都要重新計算. 第七章 會話 sessions         超文本傳輸協議(HTTP)被設計成無狀態的協議.爲了構建有效率的web應用,將從某個特定客戶機上發送來的request互相關聯起來是很必要的,會話跟蹤的技術已經發展了很長時間,但對於開發人員直接使用來說都是很困難的.         本規範定義了HttpSession接口,允許servlet容器使用好幾種方式跟蹤用戶會話,而開發人員不會陷入不同方式的細節. 7.1  會話跟蹤機制         通過HTTP cookie跟蹤會話時比較常用的辦法,所有servlet容器都要求實現這一技術.         容器發送cookie到客戶機,客戶機在接下來的請求中都將該cookie返回給容器.這樣就很清楚地將請求和會話關聯起來,用於會話跟蹤的cookie名稱一定是JSESSIONID. 7.1.2 SSL Session 7.1.3 URL重寫         URL重寫式會話跟蹤的最低公分母?,當客戶機不接受cookie時,server就使用URL重寫作爲會話跟蹤的基本方式.URL重寫,添加了附加數據(會話ID)到請求的URL路徑上.         會話ID必須被編碼作爲該URL字符串中的路徑參數。該參數的名稱爲jsessionid,例如:                 http://www.myserver.com/catalog/index.html;jsessionid=1234 7.1.4會話完整性         Web容器必須能支持HTTP會話,當處理不支持cookie使用的客戶機發送來的HTTP請求時,web容器通常使用URL重寫機制。 7.2 創建會話         一個會話被認爲是新的,只有當它是唯一一個預期會話並還沒沒有被建立。因爲,HTTP是基於request-response的協議,HTTP會話被認爲是新的,直到有客戶機加入它.當會話跟蹤信息返回服務器時,意味着一個會話已經被建立了,此時,客戶機加入了會話.直到客戶機加入會話爲止,它都不能假定下一個來自該客戶機的請求隸屬於某個會話的一部分.只要下列條件成立,會話被認爲是新的:         .客戶機還不知道該會話         .客戶機選擇不加入會話                  這些情況定義了servlet容器沒有機制將一個請求和上一個請求關聯起來.         servlet開發人員必須將它的應用設計爲可以處理客戶機沒有,不能,不會加入會話的情形. 7.3 會話範圍         HttpSession對象在應用級別(servlet context)範疇.         下列機制,例如cookie,對於不同context可以是相同的,但該對象引用,包擴屬性,容器必須按context區別開來.         用一個例子來說明:如果一個servlet使用RequestDispatcher調用屬於另一個web應用的servlet,任何對於執行調用的servlet創建的,可        見的會話信息,必須不同於被調用的servlet. 7.4 在會話中綁定屬性         servlet可以通過名稱綁定對象屬性到HttpSession的實現中.任何綁定對象對於同一servlet context下在同一會話中處理請求的其他servlet都是可用的.         會話中的一些對象被放入或是移出時,可能需要獲得通知,這可以通過實現HttpSessionBindingListener接口的對象獲得.該接口定義了下列方法,當對象被綁定或解除綁定時,發出信號.         .valueBound         .valueUnbound         valueBound方法必須在該對象通過執行HttpSession的setAttribute方法而可用之前被調用valueUnbound方法必須在該對象通過執行HttpSession的setAttribute方法而不再可用之前被調用. 7.5 會話超時         在HTTP協議中,客戶機不再活躍時沒有明確的終止信號.這意味着只有超時纔是標識客戶機不再活躍的唯一機制.         缺省的會話超時由servlet容器定義,在HttpSession接口上調用getMaxInactiveIntervalfangaf得到該值.開發人員可以使用HttpSession接口上的setMaxInactiveInterval方法改變該值.時間單位是秒.若設置爲-1,表示該會話永不過期. 7.6最後訪問時間         HttpSession接口上的getLastAccessedTime方法允許servlet判定該會話在本次請求前被訪問的最後時間.當容器第一次處理隸屬於該會話的請求時,認爲該會話被訪問.          7.7 重要的會話語義 7.7.1 線程         多個servlet執行請求線程也許同時使用一個會話對象,開發人員有責任同步對會話資源的訪問. 7.7.2 分佈式環境         在分佈式應用中,所有隸屬於某個會話的請求在某一時間必須同一個虛擬機處理,容器必須能適當地處理使用setAttribute或putValue方法放進HttpSession實例的所有對象.下列約束是強制的:         .接受的對象應實現Serializable接口         .容器可以選擇支持在HttpSession中存儲其他指定的對象,例如:EJB和事務         .移動會話將由容器具體設施處理         若放進會話的對象未實現Serializable接口,或對該類對象的支持還不可用,servlet容器可以拋出IllegalArgumentException異常,只有在容器不能支持移動會話時拋出該異常.         這些約束表明開發人員被保證沒有發生在非分佈式容器之外的併發問題.         通過擁有移動會話對象的能力,從分佈式系統中的任一個活躍節點移動到系統中的另一個節點,容器提供者能保證服務的可伸縮性和品質,負載均衡和故障轉移等特性.         如果分佈式容器堅持或移動會話來提供服務特性的品質,就不強求在序列化HttpSession和它們的屬性時使用本地虛擬機的序列化機制.容器不會保證調用會話屬性上的readObject和writeObject方法.但是保證它們的屬性可序列化關閉將被保存.         在移動會話期間,容器必須通知實現了HttpSessionActivationListener接口的會話屬性.通知鈍化監聽器必須優先於序列化監聽器,活化則要遲於會話反序列化.         應用開發人員編寫分佈式應用,應該明白因爲允許容器運行在多個java虛擬機上,他就不能依賴靜態變量來存儲應用程序狀態.應使用EJB或數據庫. 7.7.3 客戶機語義         實際上cookie和SSL認證都是由web瀏覽器控制的,而不是和瀏覽器的某個特定窗口相關聯,也許從所有窗口發送到servlet容器的請求是屬於同一個會話.爲了儘量方便,開發人員總是假定客戶機的所有窗口參加的是同一個會話. 八 轉發請求         使用RequestDispatcher接口,向另一個servlet轉發請求,或者在response中包含另一個servlet的輸出. 8.1 獲得RequestDispatcher         從ServletContext上可以獲得RequestDispatcher的實現對象:         .getRequestDispatcher         .getNamedDispatcher         getRequestDispatcher方法的參數爲一個字符串變量,描述在ServletContext範圍內的路徑.該路徑必須相對於ServletContext的根.並且以"/"開始.該方法使用此路徑尋找到servlet後,用一個RequestDispatcher對象包裝返回.如果在該路徑上沒有找到對應的servelt,一個包裝了該路徑內容的RequestDispatcher被返回.                  getNamedDispatcher方法參數爲一個字符串變量,它表示ServletContext內已知servlet的名稱,如找到該servelt,用RequestDispatcher對象包裝後返回,如未找到,返回null。                  使用相對於當前請求的相對路徑也可以獲得RequestDispatcher對象,以下方法在ServletRequest接口提供:         .getRequestDispatcher         該方法的行爲類似於ServletContext中同名函數,servlet容器使用request對象中的信息轉換給定的相對路徑爲完整的路徑。例如: 在context“/”和一個到“/garden/tools.html”的請求,此時,調用request上的getRequestDispatcher("header.html")方法效果等同於ServletContext.getRequestDispatcher("/garden/header.html")。 8.1.1 轉發請求路徑裏的查詢字符串         ServletContext和ServletRequest裏使用路徑參數獲得RequestDispatcher的方法,允許添加查詢字符串到該路徑上。例如,開發人員用以下代碼:         String path = “/raisons.jsp?orderno=5”;         RequestDispatcher rd = context.getRequestDispatcher(path);         rd.include(request, response);         查詢字符串裏指定的參數,順序要優先於同名的其他被傳進的參數。該參數與RequestDispatcher相關聯,只在include或forward調用中有效。 8.2 使用request Dispatcher         使用request Dispatcher,調用該接口上的include或forward方法。參數可以是通過service方法傳入的request,response對象,也可以是它們被包裝後的對象。         容器提供者應確保將請求分發到目的servlet必須發生在原始請求所在的虛擬機上。 8.3 include方法         該方法必須可以在任意時刻調用,目標servlet的include方法可以五約束地訪問request對象,但在訪問response對象上有一些限制。它只能向response對象的ServletOutputStream或Writer寫入信息,在response的緩衝寫完後提交response,或直接調用flushBuffer方法提交response,但不能設置頭信息,或者調用任何可能改變頭信息的方法。任何此類操作將被忽略。 8.3.1 Included參數         除了使用getNamedDispatcher獲得的servlet外,a servlet being used from within an include has access to the path by which it was invoked.         以下request屬性被設置:         javax.servlet.include.request_uri         javax.servlet.include.context_path         javax.servlet.include.servlet_path         javax.servlet.include.path_info         javax.servlet.include.query_string                 被包含的servlet可以調用getAttribute訪問這些屬性。         以getNamedDispatcher方式獲得的被包含servlet不能得到這些屬性。          8.4 Forward方法         在負責調用的servlet還沒有向客戶機提交輸出的時候,纔可以調用RequestDispatcher上的Forward方法。在目標servlet的service方法調用前,如果response緩衝中存在還沒提交的數據,這些緩衝內容必須被清空,如果response已經提交,將拋出IllegalStateException異常。request對象暴露給目的servlet的路徑元素必須反射用於獲得RequestDispatcher路徑。唯一的例外是,如果RequestDispatcher是通過 getNamedDispatcher方法獲得的。                 在forward方法返回前,response內容必須被髮送和提交,並被容器關閉。          8.4.1query string         在forward或include請求的時候,請求轉發機制負責組合查詢字符串。 8.5 錯誤處理         如果request dispatcher的目標servlet扔出運行時錯誤或一個被檢查類型的意外ServletException或IOException,它應當被傳播到調用它的servlet。所有其他異常則應被包裝爲ServletException,被傳播以前,異常引起的最初原因應被設置到原始異常。 第九章 web 應用         web應用是web server中某個特定的路徑。例如,一個catalog應用可能在http://www.mycorp.com/catalog.所有以此路徑開始的請求都被髮送到catalog應用處理。         servlet容器能建立自動產生web應用的規則,例如,~user/ 可以映射到基於/home/user/public_html/的一個web應用。         默認情形下,在任意時間內,一個web應用的實例必須運行在一個虛擬機上。但如果是分佈式應用,這是可以改變的,分佈式應用需要遵循一套更嚴格的規則,這些規則不在本規範內。 9.2 和ServletContext的關係         servlet 容器在web應用和Servlet context之間必須強制一對一的對應關係。ServletContext對象相servelt提供了整個應用視圖。 9.3 web應用的元素         web應用可以由以下元素構成:         .servlet         .JSP頁面         .工具類(Utility class)         .靜態文檔(html,image,sound 等)         .客戶端java applet,beans,和類         .組合所有以上元素的描述元信息 9.4發佈層次         本規範定義了一個層次結構,用於發佈和打包,可以文件系統形式存在,也可以以壓縮包文件形式。建議servlet容器支持此結構爲運行時表示。 9.5 目錄結構         web應用以結構化層次目錄形式存在。該層次結構的根爲文檔的根。例如,context路徑爲/catalog的web應用,應用根路徑下的index.html文件可以用/catalog/index.html請求來訪問。映射的規則在第11章有敘述。因爲應用的context路徑決定了內容的URL名字空間,web容器必須拒絕可能引起URL名字空間潛在衝突的context定義。這有可能發生,例如試圖以相同的context路徑發佈另一個web應用,或者其中一個context路徑是另一個context的一部份。匹配是大小寫敏感的,所以,衝突檢測也是一樣的。         應用層次中有個特殊的目錄叫“WEB-INF”,此目錄包含了不在應用根文檔的所有東西。WEB-INF節點不是應用文檔樹的公開部分,不能被客戶機直接訪問。但該目錄的內容對於servlet代碼是可見的,可使用ServletContext接口上的getResource或getResourceAsStream方法訪問。因此,開發人員如果需要在servlet代碼訪問,又不希望暴露給客戶機的信息,他可以放置在此目錄。WEB-INF目錄的內容有:         ./WEB-INF/web.xml         ./WEB-INF/classes/目錄存儲servlet和應用類,這些類必須可以對application class loader是可用的。         ./WEB-INF/lib/*.jar存儲java存檔文件,這些文件包含servlet,bean,和其他可用類。application class loader必須也能裝載這些存檔文件中的類。         裝載次序是先WEB-INF/classes目錄,再WEB-INF/lib目錄。 9.6 web應用存檔文件         web應用可以使用標準java存檔工具打包爲war文件. 9.7 web 應用配置描述         應該包含以下內容:         .ServletContext 初始化參數         .會話配置         .Servlet / JSP定義         .Servlet / JSP映射         .MIME類型映射         .Welcome文件列表         .Error頁面         .Security 9.7.1 擴展依賴         當大量的應用使用相同的代碼和資源,它們在容器中一般被安裝爲庫文件。這些文件通常是通用或標準的API.         應用開發人員需要知道web容器上安裝了什麼擴展部件,容器則需要知道servlet依賴什麼樣的庫。web容器應有一種機制,讓web應用可以知道JAR文件包含的資源與代碼是可用的,並使它們爲應用所用。容器應當提供一種簡便的過程可以編輯配置庫文件或是擴展部分。         推薦開發人員在war文件中使用META-INF/MANIFEST.MF列出擴展部分。若web容器不能滿足這種方式聲明的依賴,它必須拒絕應用程序,並給出錯誤信息。 9.7.2 web應用classloader         容器用來裝載WAR中的servlet的Classloader必須允許開發人員以J2SE語義使用getResource裝載任何包含在war中JAR庫內的資源。必須防止war覆蓋J2SE或java servlet API類。該classloader應該不允許servlet訪問web容器的實現類。推薦讓應用類裝載器優先裝載WAR中的類和資源,再裝載JAR中的類和資源。 9.8 替換web應用         服務器應該能夠在不重新啓動容器的情況下替換一個web應用。當應用被替換時,容器應當保持會話數據。 9.9 錯誤處理 9.9.1 request屬性         web應用必須能夠指定錯誤發生時應用使用的其他資源,這些資源的規範在配置描述中敘述。         如果錯誤定位爲servlet或JSP頁面,下列request屬性必須設定:         Request Attributes                                                                                 Type         javax.servlet.error.status_code                         java.lang.Integer         javax.servlet.error.exception_type                 java.lang.Class         javax.servlet.error.message                                         java.lang.String         javax.servlet.error.exception                                 java.lang.Throwable         javax.servlet.error.request_uri                         java.lang.String         javax.servlet.error.servlet_name                         java.lang.String         這些屬性允許servlet產生一個描述詳細錯誤信息的頁面。 9.9.2 錯誤頁面                 當sertvlet產生錯誤時,爲了允許開發人員定製返回客戶機的頁面,配置描述文件中定義了一系列錯誤頁面的描述。該語法允許容器返回配置的資源,或者當servlet設置狀態碼來表明response的錯誤,或者servlet產生傳播到容器的異常和錯誤.         若在response上設置了表明錯誤的狀態碼,容器參考錯誤頁面聲明的列表,試圖取得一個匹配的結果.         servlet處理請求時可以拋出下列異常:                  .runtime exceptions or errors         .ServletExceptions or subclasses thereof         .IOExceptions or subclasses thereof                  web應用也可以使用exception-type元素聲明錯誤頁面.容器通過比較所拋出的異常和錯誤頁面中exception-type元素的定義,返回匹配的資源.在類層次最接近的將獲得匹配.如果得不到匹配,將拋出ServletException或subclass thereof,容器將展開被包裝的異常.A second pass is made over the errorpage declarations, again attempting the match against the error page declarations,but using the wrapped exception instead.         exception-type元素必須是exception-type的class名稱唯一.類似的,status-code元素的狀套碼也必須是唯一的.         錯誤頁面機制不回干擾使用RequestDispatcher調用的servlet發生錯誤.         如果servlet產生的錯誤沒有錯誤頁處理,容器將會產生狀態碼爲500的response. 9.10 WelCome file         開發人員可以在配置描述文件中定義一個welcaome文件的順序列表.本機制的目的是允許開發人員制定目錄入口的缺省資源,如目錄缺省資源未定義,那麼到目錄入口的請求將返回一個404的response. 9.11 web應用環境         J2EE定義了命名環境,允許應用很容易地訪問資源和外部信息,webu需要顯式瞭解外部信息具體是如何命名和組織的.         正如servlet是J2EE技術的一個組件,也制定允許servlet獲得資源和EJB的引用的規範,這些元素是:         .env-entry         .ejb-ref         .ejb-local-ref         .resource-ref         .resource-env-ref         ( 本節略) 第十章 應用生命週期事件 10.1 介紹         本規範支持應用級別的事件.這些應用事件給了開發人員更大的控制能力,比使用ServletContext和HttpSession對象. 10.2 事件監聽器         應用事件監聽器是實現了一個或多個和servlet 事件監聽接口的類,在web應用被髮布的時候被實例化並在web容器中註冊。它們應由開發人員提供。         Servlet事件監聽器支持當ServletContext和HttpSession對象的狀態改變時,進行事件通知。servlet context監聽器用來管理應用程序的虛擬機級的資源和狀態。HTTP會話監聽器用來管理應用程序中與某個客戶機或用戶關聯的一些列請求的資源與狀態。         對於每種事件類型,可能有多個監聽器監聽它們。開發人員也可以指定容器調用監聽器的順序。          10.3 事件類型與監聽器接口 事件類型                 描述                                 監聽器接口 __________________________________________________________________________________________ Servlet Context 事件 生命週期                 servlet context 剛剛被創建         javax.servlet.ServletContextListener                                                 它準備好處理它的第一個請求                                                 或者context即將被關閉                         屬性改變                 servlet        context上的屬性已經        javax.servlet.ServletContextAttributesListener                                                 被添加,刪除,替換 ____________________________________________________________________________________ HTTP會話事件 生命週期                HttpSession對象已經被創建,           javax.servlet.http.HttpSessionListener                                                                 實效,或過期 屬性改變                HttpSession對象上的屬性已經           javax.servlet.HttpSessionAttributesListener                                                         被添加、刪除或替換 10.2.2 使用監聽器的例子         爲舉例說明事件的使用,我們假定一個簡單的web應用,包含很多用到數據庫的servlet。開發人員已提供了一個servlet context監聽器管理數據庫聯接。         1.當應用啓動,監聽器類被通知,應用登陸數據庫,並將聯接存儲在servlet context內。         2.web應用中的servlet可以在需要的時候訪問該聯接。         3.當web服務器關閉,或者web應用被刪除,該監聽器被通知,接着數據庫聯接被關閉。 10.3 監聽器類配置 10.3.1 提供監聽器類         應用開發人員聽實現以上四個接口的監聽器類,每個類必須有不帶參數的公共構造函數。該類被打包進WAR中,也可以放在WEB-INF/classes目錄下或者是WEB-INF/lib下的JAR中。 10.3.2 發佈聲明         在web應用配置描述文件中,使用listener元素聲明監聽器類。以類名按照調用的順序被列出。 10.3.3 註冊監聽器         web容器在應用處理第一個請求前,創建每個監聽器的實例並註冊它。容器根據監聽器實現的接口以及在配置描述文件中的順序註冊實例。容器以監聽器註冊的順序執行它們。 10.3.4 關閉時通知         當應用被關閉時,監聽器以聲明時相反的順序得到通知,,先處理會話監聽,然後是context監聽. 10.4 Example         下面例子是關於如何註冊兩個servlet context 監聽器和一個 會話監聽器的語法.         假定com.acme.MyConnectionManager和com.acme.MyLoggingModule都實現了javax.servlet.ServletContextListener,並且com.acme.MyLoggingModule         還實現了javax.servlet.HttpSessionListener,以下是配置描述:         <web-app>         <display-name>MyListeningApplication</display-name>                 <listener>                         <listener-class>com.acme.MyConnectionManager</listenerclass>                 </listener>                 <listener>                         <listener-class>com.acme.MyLoggingModule</listener-class>                 </listener>                                  <servlet>                         <display-name>RegistrationServlet</display-name>                 </servlet> </web-app>          10.5 監聽器實例與線程         容器需要在應用程序處理第一個請求之前,完成實例化監聽器類.在完成最後一個服務請求之前,容器必須維護每個監聽器實例的引用.         ServletContext和HttpSession屬性的改變是可以併發的.對屬性監聽器通知,容器不需要同步.維持狀態的監聽器類有責任保持數據的完整性,並應當明確地處理這種情況. 10.6 分佈式容器         在分佈式web容器中,HttpSession實例存在於處理該會話的請求的特定虛擬機範圍,ServletContext對象的範圍則在web容器所在的虛擬機內.分佈式容器不需要將servlet context和session上的        事件傳播到其他虛擬機.監聽器實例範圍則在每個虛擬機上的每個部署聲明對應一個.          10.7 會話事件         開發人員使用監聽器類跟蹤應用會話.它的作用很大,想知道哪個會話因容器使會話超時,或是因爲被調用了invalidate方法而失效了。區別在於是直接使用HTTPSession的API還是間接使用監聽器。 第十一章 映射請求到Servlet          收到客戶機的請求,web容器首先判斷由哪個web應用處理它。被選定的應用擁有最長的匹配該請求URL的context路徑,和URL的匹配部分就是context path.          web容器接下來必須使用路徑映射過程定位處理請求的servlet:          用來映射到servlet的路徑是請求的URL減去context path,下列的URL映射規則其順序是有用的,一個成功的匹配後就不需要進行下一步的匹配了:                   1.容器嘗試找到請求路徑到servlet路徑的精確匹配,成功就選定該servlet。          2.容器將回退嘗試匹配最長的路徑前綴:使用"/"字符作爲路徑符,每次沿着路徑向下一步查找目錄。按最長的那個匹配選擇servlet.          3.如果URL最後的那段包含擴展名(即.jsp),servlet容器將試圖匹配一個處理該擴展名的servlet。擴展名是最後一個"."後面的這部分。          4.如果上述都沒有找到匹配的servlet,容器嘗試serve content appropriate for the resource requested.如“default"servlet定義了,就使用default servlet。          11.2 映射規範          以下語法用於在應用配置描述中定義映射:          .以'/'開頭,'/*'結尾的後綴被用來路徑映射          .以'*.'開始的前綴被用來映射擴展名          .只包含'/'的字符串表示應用的缺省servlet,此時,servlet path是請求的URI減去context path,path info 爲null.          .所有其他字符串只是被用來做精確匹配.          11.2.1 隱含的映射         若容器擁有內部的JSP容器,所有"*.jsp" 擴展被映射到它,允許執行JSP頁面。這就是隱含映射。如Web 應用定義了*.jsp映射,將優先於隱含映射。          只要顯式映射優先,servlet容器也可以做其他隱含映射。例如:*.shtml可以映射用來包含。          11.2.2映射例子         path pattern                         servlet         /foo/bar/*                         servlet1         /baz/*                                 servlet2         /catalog                                 servlet3         *.bop                                 servlet4                          incoming path                         servlet handling request         /foo/bar/index.html                         servlet1         /foo/bar/index.bop                         servlet1         /baz                                 servlet2         /baz/index.html                         servlet2         /catalog                                 servlet3         /catalog/index.html                         “default” servlet         /catalog/racecar.bop                servlet4         /index.bop                         servlet4          第十二章 安全         開發人員創建出web應用以後,將其贈與、銷售或者傳送到發佈者,並安裝到運行環境中。開發人員需要和發佈者溝通如何給安裝的應用程序         設置安全。利用配置描述機制完成此項工作。         本章描述了安全需求的發佈表示。和web應用目錄結構與配置描述類似,本章並不描述運行表現需求。推薦容器實現本章作爲它們的運行表示。          12.1 介紹                 web應用包含的資源可以被很多用戶訪問。在開放網絡特別是internet,這些資源通常可以被無保護的訪問。在這樣的環境下,大量的web應用都有安全需求。                 雖然質量管理和實施細節可能不同, servlet容器的機制和基礎設施可以達到分享一些以下要求:                                  .認證(Authentication:):通信的個體互相證明他們就代表着被批准爲訪問的那個指定的身分。                 .資源訪問控制:出於增強完整性、機密性、有效性的約束,與資源的交互被限制在某些用戶或程序的集合內。                 .數據完整性:證明數據在傳輸過程中未被第三方篡改。                 .機密性和數據保密:信息只對被批准訪問它的用戶可用。                  12.2 聲明安全                         聲明安全涉及表示應用安全結構的方式,包括角色,訪問控制,外部對應用認證需求形式。配置描述是聲明web應用安全的主要工具。                         發佈者映射應用的邏輯安全需求到針對運行環境特定的安全策略。運行時,servlet容器使用安全策略增強認證和授權。                         安全模型適用於web應用的靜態內容部分和servlet。當servlet使用RequestDispatcher對象調用靜態資源或servlet使用forward或include,安全模型是不應用的。                          12.3 安全編程                 當只使用聲明性的安全措施不能滿足應用安全模型的需要時,可進行安全方面的編程。由下列HttpServletRequest接口的方法組成:                 .getRemoteUser                 .isUserInRole                 .getUserPrincipal                                  getRemoteUser方法返回客戶機用來認證的用戶名稱。isUserInRole方法判斷是否遠程用戶隸屬於某個安全角色。getUserPrincipal方法                 判斷當前用戶的Principal,並返回一個java.security.Principal對象。這些方法允許servlet根據獲得的信息作出商業邏輯層的判斷。                 如果用戶沒有通過認證,getRemoteUser方法返回NULL.isUserInRole則總是返回false,getUserPrincipal方法返回null。                 isUserInRole方法有一個字符串類型的參數代表用戶角色名稱,配置描述中應聲明security-role-ref元素,同時聲明role-name子元素,此元素的內容將被傳遞進該方法。                 security-role元素應包含一個role-link子元素,其值就是此用戶被映射的安全角色名稱。決定調用的返回值時,容器使用security-role-ref到security-role的映射。                 例如:映射安全引用"FOO"到角色名爲"manager"的安全角色的語法如下:                 <security-role-ref>                         <role-name>FOO</role-name>                         <role-link>manager</manager>                 </security-role-ref>                 此例中,如屬於“manager”角色的用戶調用了此servlet,isUserInRole("FOO")方法將返回true。                 如果security-role-ref匹配security-role元素未被聲明,容器必須默認逆着security-role元素列表檢查role-name元素參數。                 isUserInRole方法則相關於調用者是否映射到了安全角色。開發人員必須知道使用默認機制也許限制了其靈活性,在改變角色名稱而不必要重新編譯發起調用的servlet。                  12.4 角色         安全角色是由應用開發人員或集成者定義的邏輯用戶組。當發佈應用時,角色釉發佈者映射到運行環境的principal或組。         Servlet容器根據principal的安全屬性,爲與請求相關的principal執行聲明的或編程的安全。         1.發佈者已經映射了一個安全角色到操作系統內的一個用戶組。正在調用的用戶組隸屬於哪個principal,可在其安全屬性中檢索到。         當principal的用戶組匹配映射了安全角色的用戶組時,principal隸屬於安全角色。         2.發佈者在安全策略域中已經爲principal名稱映射了安全角色。在這種情況下,可從其安全屬性中檢索到正在調用的principal的名稱.         只有當principal的名字和安全角色映射的principal名字一樣時,principal隸屬於安全角色。          12.5 認證         web 客戶機使用下列機制向服務器認證用戶:         .HTTP基本認證         .HTTP摘要認證         .HTTPS客戶端認證         .基於Form認證          12.5.1         HTTP基本認證         HTTP基本認證,基於用戶名和密碼,是HTTP/1.1規範定義的認證機制。Web服務器要求web客戶端認證用戶。作爲請求的一部分,web服務器傳遞"領域"(字符串),包含被認證的用戶信息。用於基本認證的領域字符串並不附加任何特殊安全策措施。Web客戶機將用戶名和用戶密碼傳給服務器。然後,web服務器在指定的領域內認證用戶。         基本認證並非安全的認證協議,用戶密碼以簡單的base64編碼發送。並且目標服務器也不需要被認證。額外的保護可以減輕一些安全憂慮:比如安全傳輸機制(HTTPS)        ,或者網絡層安全(IPSEC協議或VPN策略)都是經常被使用的。          12.5.2 HTTP摘要認證         象HTTP基本認證一樣,HTTP摘要認證也用用戶名和密碼的形式給用戶授權。但認證的密碼被加密,當然比HTTP基本認證使用的base64編碼安全得多。HTTPS客戶端認證,象摘要認證一樣,目前不被廣泛使用,servlet容器支持它不是必須的,但值得鼓勵。          12.5.3 基於Form的認證         使用“登陸屏幕”這種內建在web瀏覽器內的認證機制看上去感覺缺乏變化。本規範介紹介紹基於form認證機制,它允許開發人員控制登陸屏幕的外觀。         web應用配置描述包含登陸form和錯誤頁面的入口,登陸form必須包含用戶名和密碼的輸入域。這些輸入域必須分別命名爲j_username和j_password。         當用戶試圖當問受保護的web資源,容器檢驗用戶的認證。如果用戶通過認證,擁有權限訪問該資源,該資源被激活,返回它的引用。如果用戶未通過認證,則:         1.與安全約束關聯的登陸form被髮送到客戶端,而引發認證的URL被容器存儲。         2.用戶填寫form。         3.客戶機將form發送回服務器。         4.容器試圖使用form裏的信息認證用戶         5.若認證失敗,適用formward或redirect導航到錯誤頁面,將response的狀態碼設定爲401。         6.如果認證成功,被認證的用戶的principal被檢查看是否它在一個已授權的角色中.         7.如果認證成功,客戶機被重新導航到到前面所存儲的URL路徑。                  發送給未通過認證的用戶的錯誤頁包含關於失敗的信息。         基於form認證和基本認證一樣缺乏安全,因爲用戶密碼是明碼傳輸,而且目的服務器也未經認證。通過附加的保護可以減輕這些安全憂慮:例如安全傳輸機制(HTTPS),網絡層安全(IPSEC或VPN)。 12.5.3.1 登陸form         基於form登陸和基於URL的會話跟蹤一起使用是有問題的,實現基於form登陸應當只在通過cookie方式的會話或SSL會話時使用。         爲了使認證能過程正確執行,登陸form的action必須是j_security_check,此約束是爲了使登陸form 面對所請求的任何資源都可以工作得很好,並避免要求服務器指定action域。         <form method=”POST” action=”j_security_check”>                 <input type=”text” name=”j_username”>                 <input type=”password” name=”j_password”>         </form>                  如果該登陸form由一個帶參數的HTTP請求引起,容器必須保存原始的請求參數,當認證成功後,再將其轉發到被請求的資源。         如果被認證的用戶使用登陸form,並且已創建了HTTP 會話,該會話的超時或失效導致該用戶登出,其接下來的請求會引起用戶再次認證.         登出的範圍和認證是一樣的. 例如:如果容器支持single-signon,J2EE技術兼容的web容器,用戶只需要認證web容器中的所有應用任何一個就可以了. 12.5.4 HTTPS客戶端認證         使用HTTPS的終端用戶認證是強認證機制.此機制要求用戶擁有公共密鑰證書(PKC),PKC對於電子商務應用是很有用的,不兼容J2EE技術的servlet容器不需要支持HTTPS協議.          12.6 服務器跟蹤認證信息         下列安全身份在運行環境中映射的角色由運行環境指定而非應用程序所指定的.                  1.使登陸機制和策略成爲要發佈web應用的環境的屬性.         2.對於同一容器內的所有應用可以使用相同的認證信息.         3.只有安全策略域的邊界交叉的時候,才需要用戶重新認證.         因此,servlet容器需要在容器層次(非web應用層)跟蹤認證信息,允許在一個web應用中認證後的用戶可以訪問容器用同樣安全身份管理的其他資源.          12.7 EJB調用裏的安全身份傳播         調用企業bean必須提供安全身份或principal.從web應用中調用企業bean的默認模式是將web用戶的安全身份傳播到EJB容器.         在另一些場景中,web容器需要允許對於它或者EJB容器來說不認識的用戶調用:         1.web容器需要支持還沒有認證的客戶機訪問web資源.         2.應用代碼也許是基於訪問者身份的數據和signon的唯一處理者.         在這些情況下,web應用配置描述,可以指定一個run-as元素,容器必須根據定義在run-as元素內的安全角色的名字,將調用者的安全身份傳播到EJB層.         該安全角色的名字必須是web應用定義的安全角色中的一個.         因爲web容器作爲J2EE平臺的一部份運行,調用在相同或不同J2EE應用中的EJB組件,run-as元素都必須被支持.          12.8 指定安全約束         安全約束是給與網絡內容以預期保護的一種聲明性方式。包含以下元素:         .web資源集合         .授權約束         .用戶數據約束                  web資源集合是一系列的URL範式和描述需要保護的一系列資源的HTTP方法。所有路徑匹配URL範式的請求遵循此約束。         容器匹配預定義與安全約束內的URL範式的短髮與11.1是一致的。                  授權限制是一套安全角色,訪問網資源集合描述的資源的用戶必須屬於其中之一。如果用戶不是被允許角色的一部分,用戶被拒絕訪問該資源.         如果授權約束爲定義角色,那麼沒有用戶可以訪問web應用中被此安全約束定義的這一部分.                  用戶數據描述了對客戶機服務器傳輸層的需求.此需求的目的是內容一致性(防止通信過程中的破壞)或是機密性(防止傳輸中被竊聽).容器必須至少使用SSL響應標誌爲 integral或confidential.的請求.如果原始請求的協議是HTTP,容器必須重新導向客戶機到HTTPS端口.          12.9 默認策略         默認情況下,訪問資源無需認證,只有在配置描述中指定了的才需要認證.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章