一個 Web 應用是由許多 servlet、 HTML 頁面、類和其餘資源組成的集合,這些資源組成了一個運行在 Web
服務器上的完整應用程序。 Web 應用程序可以捆綁和運行在來自不一樣提供商的不一樣容器上。html
在 Web 服務器中 Web 應用程序的根目錄是一個特定的路徑。例如,一個 catalog 應用,能夠位於
http://www.mycorp.com/catalog
。以這個前綴開始的全部請求將被路由到表明 catalog 應用的 ServletContext
環境中。java
servlet 容器可以制定 Web 應用程序自動生成的規則。例如,一個~user/
映射可用於映射到一個基於/home/user/public_html/
的 Web 應用。web
默認狀況下,在任什麼時候候一個 Web 應用程序的實例必須運行在一個虛擬機( VM)中。若是應用程序經過其部署描述文件標記爲「分佈式」的,那麼能夠覆蓋此行爲。標記爲分佈式的應用程序必須遵照比普通的 Web應用程序更嚴格的規則。本規範中陳述了這些規則。安全
ServletContext
的關係servlet 容器必須強制 web 應用程序和ServletContext
之間一對一進行通訊。ServletContext
對象提供了一個servlet 和它的應用程序視圖。服務器
Web 應用程序可能包括如下項目:app
本規範定義了一個用於部署和打包用途的,可存在於開放文件系統、歸檔文件或一些其餘形式中的層次結構。建議 servlet 容器支持這種結構做爲運行時表示形式,但不是必須的。webapp
一個 Web 應用程序以結構化的目錄層次結構存在。層次結構的根目錄做爲文件的歸檔目錄,這些文件是應用的一部分。例如,對於 Web 容器中一個 Web 應用程序的上下文路徑/catalog
,在 Web 應用程序層次結構中的 index.html
文件,或在 WEB-INF/lib
目錄下的 JAR 文件中的 META-INF/resources
目錄下包括的index.html
文件,能夠知足從/catalog/index.html
送達的請求。若是在根上下文中和應用的 WEB-INF/lib
目錄下的 JAR 文件中的 META-INF/resources
目錄中都存在一個 index.html
文件,那麼必須使用根上下文中的index.html
。匹配的 URL 到上下文路徑的規則安排在第 12 章: 「請求映射servlet」中。因爲應用的上下文路徑肯定了 Web 應用內容的 URL 命名空間, Web 容器必須拒絕 Web 應用定義的上下文路徑,由於可能在這個 URL 命名空間中致使潛在的衝突。例如,試圖部署兩個具備相同上下文路徑的 Web 應用時可能發生這種狀況。因爲把請求匹配到資源是區分大小寫的,因此在肯定潛在衝突時也必須區分大小寫。異步
應用程序層次結構中存在一個名爲「WEB-INF
」的特殊目錄。這個目錄包含了與應用程序相關的全部東西,這些東西不在應用程序的歸檔目錄中。大多數 WEB-INF 節點都不是應用程序公共文檔樹的一部分。除了靜態資源和 WEB-INF/lib
目錄下打包在 JAR 文件中 META-INF/resources
目錄下的 JSP 文件以外, WEB-INF目錄下包含的其餘任何文件都不能由容器直接提供給客戶端訪問。然而, WEB-INF 目錄中的內容能夠經過 servlet 代 碼 調 用 ServletContext
的 getResource
和 getResourceAsStream
方 法 來 訪 問 , 並 可 使 用RequestDispatcher
調用公開這些內容。所以,若是應用開發人員想經過 servlet 代碼訪問這些內容,而不肯意直接對客戶端公開應用程序指定配置信息,那麼能夠把它放在這個目錄下。因爲把請求匹配到資源的映射區分大小寫,例如,客戶端請求‘/WEB-INF/foo
’, ‘/WEb-iNf/foo
’,不該該返回位於/WEB-INF 下的 Web 應用程序的內容,也不該該返回其中任何形式的目錄列表。jsp
WEB-INF 目錄中的內容有:分佈式
/WEB-INF/web.xml
部署描述文件。/WEB-INF/classes/
。此目錄中的類對應用程序類加載器必須是可見的。/WEB-INF/lib/*.jar
。這些文件中包括了 servlet, beans,靜態資源和打包在 JAR 文件中的 JSP 文件,以及其餘對 Web 應用程序有用的實用工具類。 Web 應用程序的類加載器必須可以從這些歸檔文件中加載類。Web 應用程序類加載器必須先從 WEB-INF/classes
目錄下加載類,而後從 WEB-INF/lib
目錄下的 JAR 庫中加載。此外,除了靜態資源打包在 JAR 文件中的狀況外,任何來自客戶端的請求訪問 WEB-INF/
目錄中的資源必須返回一個 SC_NOT_FOUND
( 404)的響應。
下面是一個示例 Web 應用程序的文件清單:
/ |-/index.html |-/howto.jsp |-/feedback.jsp |-/images |-/banner.gif |-/jumping.gif /WEB-INF |-/web.xml |-/lib |-/jspbean.jar |-/catalog.jar!/META-INF/resources/catalog/moreOffers/books.html |-/classes |-/com/mycorp/servlets/MyServlet.class |-/com/mycorp/util/MyUtils.class
可使用標準的 Java 歸檔工具把 Web 應用程序打包並簽名到一個 Web 存檔格式( WAR)文件中。例如,一個關於「issue tracking」的應用程序能夠分佈在一個稱爲 issuetrack.war
的歸檔文件中。
當打包成這種形式時,將生成一個 META-INF
目錄,其中包含了對 java 歸檔工具備用的信息。儘管這個目錄的內容能夠經過 servlet 代碼調用 ServletContext
的 getResource
和 getResourceAsStream
方法來訪問,容器也不能把這個目錄看成內容來響應客戶端請求。此外,任何請求訪問 META-INF
目錄中的資源必須返回一個 SC_NOT_FOUND
( 404)的響應。
Web 應用程序部署描述文件(見第 14 章, 「部署描述文件」)的配置和部署信息包括如下幾種類型:
當許多應用程序使用相同的代碼或資源,一般將它們安裝在容器的庫文件中。這些文件每每是通用的或標準的 API,能夠在不犧牲可移植性的狀況下使用。僅由一個或幾個應用程序使用的文件將做爲 Web 應用程序的一部分來訪問。容器必須爲這些庫提供一個目錄。放置在這個目錄中的文件必須對全部的 Web 應用可
見。此目錄的位置由容器指定。 servlet 容器用於加載這些庫文件的類加載器必須和在同一個 JVM 中的全部 Web 應用的類加載器相同。這個類加載器的實例必須在 Web 應用程序類加載器的父類加載器鏈中。
爲了保持可移植性,應用程序開發人員須要知道 Web 容器中安裝了哪些擴展,而容器須要知道 WAR 中的servlet 依賴哪些庫。
依 賴 這 樣 的 擴 展 的 應 用 開 發 人 員 必 須 在 WAR 文 件 中 提 供 一 個 列 出 所 有 WAR 文 件 所 需 擴 展 的META-INF/MANIFEST.MF
文件。清單文件的格式應該遵循標準的 JAR 清單格式。在部署 Web 應用程序的時候, Web 容器必須使正確的擴展版本對遵循可選包版本控制( Optional Package Versioning)機制 定義的規則的應用程序可見。
Web 容器也必須可以識別出 WAR 文件中 WEB-INF/lib
目錄下的任意一個 JAR 包中的清單文件聲明的依賴關係。
若是 Web 容器不可以知足以這種方式聲明的依賴關係,它應該使用一條有意義的錯誤消息拒絕該應用程序。
容器用於加載 WAR 文件中 servlet 的類加載器必須容許開發人員使用 getResource
加載遵循正常 JavaSE 語義的 WAR 文件的 JAR 包中包含的任何資源。和 Java EE 許可協議中描述的同樣,不屬於 Java EE 產品的 servlet 容器不該該容許應用程序覆蓋 Java SE 平臺中的類,如在 java.
和 javax.
命名空間中的類, Java SE不容許進行修改。容器不該該容許應用程序覆蓋或訪問容器的實現類。同時建議應用程序類加載器實現成WAR 文件中的類和資源優先於屬於容器範圍內的 JAR 包中的類和資源加載。一個類加載器的實現必須保證對部署到容器的每一個 web 應用,調用 Thread.currentThread.getContextClassLoader()
返回一個實現了本節規定的約定的 ClassLoader
實例。此外,部署的每一個 Web 應用程序的 ClassLoader
實例必須是一個單獨的實例。容器必須在任何回調(包括偵聽器回調)到 Web 應用程序以前設置上面描述的線程上下文ClassLoader
,一旦回調返回,須要把它設置成原來的 ClassLoader
。
服務器應該可以更新一個新版本的應用程序,而無需重啓容器。當一個應用程序更新時,容器應提供一個可靠的方法來保存該應用程序的會話數據。
在發生錯誤時, Web 應用程序必須可以詳細說明,應用程序中的其餘資源被用來提供錯誤響應的內容主體。這些資源的規定在部署描述文件中配置。
若是錯誤處理位於一個 servlet 或 JSP 頁面:
RequestDispatcher.forward
跳轉到已經完成的錯誤資源同樣。表 10-1 請求屬性和它們的類型
請求屬性 | 類型 |
---|---|
javax.servlet.error.status_code | java.lang.Integer |
javax.servlet.error.exception_type | java.lang.Class |
javax.servlet.error.message | java.lang.Class |
javax.servlet.error.exception | java.lang.Throwable |
javax.servlet.error.request_uri | java.lang.String |
javax.servlet.error.servlet_name | java.lang.String |
這些屬性容許 servlet 根據狀態碼、異常類型、錯誤消息、傳播的異常對象、發生錯誤時由 servlet 處理的請求 URI(像調用 getRequestURI 方法肯定的 URI 同樣)、以及發生錯誤的 servlet 的邏輯名稱來生成專門的內容。
因爲本規範的 2.3 版本引入了異常對象屬性列表,異常類型和錯誤消息屬性是多餘的。他們保留向後兼容早期的 API 版本。
爲了使開發人員可以在 servlet 產生一個錯誤時自定義內容的外觀返回到 Web 客戶端,部署描述文件中定義了一組錯誤頁面說明。這種語法容許當 servlet 或過濾器調用 response 的 sendError
方法指定狀態碼時,或若是 servlet 產生一個異常或錯誤傳播給容器時,由容器返回資源配置。
若是調用 response 的 sendError
方法,容器參照爲 Web 應用聲明的錯誤頁面列表,使用狀態碼語法並試圖匹配一個錯誤頁面。若是找到一個匹配的錯誤頁面,容器返回這個位置條目指示的資源。
在處理請求的時候 servlet 或過濾器可能會拋出如下異常:
ServletException
或它的子類異常IOException
或它的子類異常Web 應用程序可使用 exception-type
元素聲明錯誤頁面。在這種狀況下,容器經過比較拋出的異常與使用 exception-type
元素定義的 error-page
列表來匹配異常類型。在容器中的匹配結果返回這個位置條目指示的資源。在類層次中最接近的匹配將被返回。
如 果 聲 明 的 error-page
中 沒 有 包含 exception-type
適 合使 用 的 類 層 次 結 構 的 匹 配 , 那 麼 拋 出 一 個 ServletException
異常或它的子類異常,容器經過 ServletException.getRootCause
方法提取包裝的異常。第二遍經過修改錯誤頁面聲明,使用包裝的異常再次嘗試匹配聲明的錯誤頁面。
使用 exception-type
元素聲明的 error-page
在部署描述文件中必須惟一的,由 exception-type
的類名決定它的惟一性。一樣地, 使用 status-code
元素聲明的 error-page
在部署描述文件中必須是惟一的,由狀態碼決定它的惟一性。
若是部署描述中的一個 error-page
元素沒包含一個 exception-type
或 error-code
元素,錯誤頁面時默認的錯誤頁面。
當錯誤發生時,錯誤頁面機制不會干預調用使用 RequestDispatcher
或 filter.doFilter
方法。用這種方法,過濾器或 Servlet 有機會使用 RequestDispatcher
處理產生的錯誤。
若是上述錯誤頁面機制沒有處理 servlet 產生的錯誤,那麼容器必須確保發送一個狀態 500
的響應。
默認的 servlet 和容器將使用 sendError
方法,發送 4xx
和 5xx
狀態的響應,這樣錯誤機制纔可能會被調用。
默認的 servlet 和容器將使用 setStatus
方法,設置 2xx
和 3xx
的響應,並不會調用錯誤頁面機制。
若是應用程序使用第 2.3.3.3 節,第 2-10 頁「異步處理」中描述的異步操做,那麼處理應用程序建立的線程的全部錯誤是應用程序的職責。容器應該經過 AsyncContext.start
方法注意線程發出的錯誤。對於處理AsyncContext.dispatch
過程當中發生的錯誤,請參照第 2-16 頁中看到的幾節, 「執行 dispatch
方法的時候可能發生的錯誤或異常必須被容器按照以下的方式捕獲並處理」。
錯誤頁面機制運行在由容器建立的原來未包裝過的或未通過過濾的 request 或 response 對象上。在第 6.2.5 節「過濾器和請求轉發」中描述的機制能夠在產生一個錯誤響應以前用來指定要應用的過濾器。
Web 應用程序開發人員能夠在 Web 應用程序部署描述文件中定義一個稱爲歡迎文件的局部 URI 有序列表。在 Web 應用程序部署描述文件模式中描述了部署描述文件中歡迎文件列表的語法。
這種機制的目的是,當一個對應到 WAR 文件中一個目錄條目的請求 URI 沒有映射到一個 Web 組件時,容許部署者爲容器用於添加 URI 指定局部 URI 有序列表。這種請求被認爲是有效的局部請求。
通 過 下 面 常 見 的 例 子 來 明 確 這 種 用 法 的 便 利 : 可 以 定 義‘index.html
’ 歡 迎 文 件 , 以 便 像 請 求 URL host:port/webapp/directory/
,其中‘directory
’是 WAR 文件中的一個不能映射到 servlet 或 JSP 頁面的條目,如下面的形式返回給客戶端: ‘host:port/webapp/directory/index.html
’。
若是 Web 容器接收到一個有效的局部請求, Web 容器必須檢查部署描述文件中定義的歡迎文件列表。歡迎文件列表是一個沒有尾隨或前導 /
的局部 URL 有序列表。 Web 服務器必須把部署描述文件中按指定順序的每一個歡迎文件添加到局部請求,並檢查 WAR 文件中的靜態資源是否映射到請求 URI。 Web 服務器必須再
把部署描述文件中按指定順序的每一個歡迎文件添加到局部請求,並檢查 servlet 是否映射到請求 URI。 Web 容器必須將請求發送到 WAR 文件中第一個匹配的資源。容器可以使用轉發、重定向、或容器指定的機制將請求發送到歡迎資源,這與直接請求沒有什麼區別。
若是按上述的方式沒有找到匹配的歡迎文件,容器可能會使用它認爲合適的方式處理該請求。對於有的配置來講,這可能意味着返回一個目錄列表,對其餘配置來講可能返回一個 404
響應。
考慮一個 Web 應用程序:
部署描述文件列出瞭如下的歡迎文件。
<welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list>
WAR 文件中的靜態內容以下
/foo/index.html /foo/default.jsp /foo/orderform.html /foo/home.gif /catalog/default.jsp /catalog/products/shop.jsp /catalog/products/register.jsp
請求 URI /foo
將被重定向到 URI /foo/
。
請求 URI /foo/
將返回/foo/index.html
的。
請求 URI /catalog
將被重定向到 URI /catalog/
。
請求 URI /catalog/
將返回/catalog/default.jsp
。
請求 URI /catalog/index.html
將致使 404
未找到錯誤。
請求 URI /catalog/products
將重定向到 URI /catalog/products/
。
請求 URI /catalog/products/
將被傳遞給「默認」的 servlet(若是有默認的 servlet 的話)。若是沒有映射到「默認」的 servlet,請求可能會致使一個 404
未找到錯誤,可能會致使一個包括 shop.jsp
和 register.jsp
目錄列表,或可能致使容器定義的其餘行爲。請參見 12.2 節, 「映射規範」定義的「默認」servlet。
全部上述的靜態內容均可以打包到 JAR 文件的 META-INF/resources
目錄中。這個 JAR 文件能夠放到 Web
應用的 WEB-INF/lib
目錄下。
servlet 容器不屬於 JavaEE 技術標準的實現,鼓勵實現這個容器但不是必需的,實現應用環境的功能請參見第 15.2.2 節中描述的「Web 應用環境」和 JavaEE 規範。若是他們沒有實現須要支持這種環境的條件,根據部署依賴它們的應用程序,容器應該提供一個警告。
當一個 Web 應用程序部署到容器中,在 Web 應用程序開始處理客戶端請求以前,必須按照下述步驟順序執行。
<listener>
元素標識的每一個事件監聽器的一個實例。ServletContextListener
接口的監聽器實例,調用 contextInitialized()
方法。<filter>
元素標識的每一個過濾器的一個實例,並調用每一個過濾器實例的 init()
方法。<load-on-startup>
元素的<servlet>
元素,根據 load-on-startup
元素值定義的順序爲每一個 servlet 實例化一個實例,並調用每一個 servlet 實例的 init()
方法。若是 Web 應用不包含任何 servlet、過濾器、或監聽器組件或使用註解聲明相同的,那麼能夠不須要 web.xml
文件。換句話說,只包含靜態文件或 JSP 頁面的應用程序並不須要一個 web.xml
的存在。