J2EE應用程序的Web層狀態復制
大多數具有一定重要性的 Web 應用程序都要求維護某種會話狀態,如用戶購物車的內容。如何在群集服務器應用程序中管理和復制狀態對應用程序的可伸縮性有顯著影響。許多 J2SE 和 J2EE 應用程序將狀態存儲在由 Servlet API 提供的 HttpSession 中。本文作者分析了狀態復制的一些選項以及如何最有效地使用 HttpSession 以提供好的伸縮性和性能。
不管正在構建的是 J2EE 還是 J2SE 服務器應用程序,都有可能以某種方式使用 Java Servlet —— 可能是直接地通過像 JSP 技術、Velocity 或者 WebMacro 這樣的表示層,也可能通過一個基于 servlet 的 Web 服務實現,如 Axis 或者 Glue。Servlet API 提供的一個最重要的功能是會話管理 —— 通過 HttpSession 接口進行用戶狀態的認證、失效和維護。
會話狀態
幾乎每一個 Web 應用程序都有一些會話狀態,這些狀態有可能像記住您是否已登錄這么簡單,也可能是您的會話的更詳細的歷史,如購物車的內容、以前查詢結果的緩存或者 20 頁動態問卷表的完整響應歷史。因為 HTTP 協議本身是無狀態的,所以需要將會話狀態存儲在某處并與瀏覽會話以某種方式相關聯,使得下次請求同一 Web 應用程序的頁面時可以容易地獲取。幸運的是,J2EE 提供了幾種管理會話狀態的方法 —— 狀態可以存儲在數據層,用 Servlet API 的 HttpSession 接口存儲在 Web 層,用有狀態會話 bean 存儲在 Enterprise JavaBeans(EJB)層,甚至用 cookie 或者隱藏表單字段將狀態存儲在客戶層。不幸的是,會話狀態管理不當會帶來嚴重的性能問題。
如果應用程序能夠在 HttpSession 中存儲用戶狀態,這種方法通常比其他方法更好。在客戶端用 HTTP cookie 或者隱藏表單字段存儲會話狀態有很大的安全風險 —— 它將應用程序的一部分內部內容暴露給了非受信任的客戶層。(一個早期的電子商務網站將購物車內容(包括價格)存儲在隱藏表單字段中,從而可以很容易被非法利用,讓任何了解 HTML 和 HTTP 的用戶可以以 0.01 美元購買任何商品。噢)此外,使用 cookie 或者隱藏表單字段很混亂,容易出錯,并且脆弱(如果用戶禁止在瀏覽器中使用 cookie,那么基于 cookie 的方法就完全不能工作)。
在 J2EE 應用程序中存儲服務器端狀態的其他方法是使用有狀態會話 bean,或者在數據庫中存儲會話狀態。雖然有狀態會話 bean 在會話狀態管理方面有更大的靈活性,但是在可能的情況下,將會話狀態存儲在 Web 層仍然有好處。如果業務對象是無狀態的,那么通常可以僅僅添加更多 Web 服務器來擴展應用程序,而不用添加更多 Web 服務器和更多 EJB 容器, 這樣的成本一般要低一些并且容易完成。使用 HttpSession 存儲會話狀態的另一個好處是 Servlet API 提供了一種會話失效時通知的容易方法。在數據庫中存儲會話狀態的成本可能難以承受。
servlet 規范沒有要求 servlet 容器進行某種類型的會話復制或者持久性,但是它建議將狀態復制作為 servlet 首要 存在理由(raison d'etre) 的重要部分,并且它對作為進行會話復制的容器提出了一些要求。會話復制可以提供大量好處 —— 負載平衡、伸縮性、容錯和高可用性。相應地,大多數 servlet 容器支持某種形式的 HttpSession 復制,但是復制的機制、配置和時間是由實現決定的。
不管正在構建的是 J2EE 還是 J2SE 服務器應用程序,都有可能以某種方式使用 Java Servlet —— 可能是直接地通過像 JSP 技術、Velocity 或者 WebMacro 這樣的表示層,也可能通過一個基于 servlet 的 Web 服務實現,如 Axis 或者 Glue。Servlet API 提供的一個最重要的功能是會話管理 —— 通過 HttpSession 接口進行用戶狀態的認證、失效和維護。
會話狀態
幾乎每一個 Web 應用程序都有一些會話狀態,這些狀態有可能像記住您是否已登錄這么簡單,也可能是您的會話的更詳細的歷史,如購物車的內容、以前查詢結果的緩存或者 20 頁動態問卷表的完整響應歷史。因為 HTTP 協議本身是無狀態的,所以需要將會話狀態存儲在某處并與瀏覽會話以某種方式相關聯,使得下次請求同一 Web 應用程序的頁面時可以容易地獲取。幸運的是,J2EE 提供了幾種管理會話狀態的方法 —— 狀態可以存儲在數據層,用 Servlet API 的 HttpSession 接口存儲在 Web 層,用有狀態會話 bean 存儲在 Enterprise JavaBeans(EJB)層,甚至用 cookie 或者隱藏表單字段將狀態存儲在客戶層。不幸的是,會話狀態管理不當會帶來嚴重的性能問題。
如果應用程序能夠在 HttpSession 中存儲用戶狀態,這種方法通常比其他方法更好。在客戶端用 HTTP cookie 或者隱藏表單字段存儲會話狀態有很大的安全風險 —— 它將應用程序的一部分內部內容暴露給了非受信任的客戶層。(一個早期的電子商務網站將購物車內容(包括價格)存儲在隱藏表單字段中,從而可以很容易被非法利用,讓任何了解 HTML 和 HTTP 的用戶可以以 0.01 美元購買任何商品。噢)此外,使用 cookie 或者隱藏表單字段很混亂,容易出錯,并且脆弱(如果用戶禁止在瀏覽器中使用 cookie,那么基于 cookie 的方法就完全不能工作)。
在 J2EE 應用程序中存儲服務器端狀態的其他方法是使用有狀態會話 bean,或者在數據庫中存儲會話狀態。雖然有狀態會話 bean 在會話狀態管理方面有更大的靈活性,但是在可能的情況下,將會話狀態存儲在 Web 層仍然有好處。如果業務對象是無狀態的,那么通常可以僅僅添加更多 Web 服務器來擴展應用程序,而不用添加更多 Web 服務器和更多 EJB 容器, 這樣的成本一般要低一些并且容易完成。使用 HttpSession 存儲會話狀態的另一個好處是 Servlet API 提供了一種會話失效時通知的容易方法。在數據庫中存儲會話狀態的成本可能難以承受。
servlet 規范沒有要求 servlet 容器進行某種類型的會話復制或者持久性,但是它建議將狀態復制作為 servlet 首要 存在理由(raison d'etre) 的重要部分,并且它對作為進行會話復制的容器提出了一些要求。會話復制可以提供大量好處 —— 負載平衡、伸縮性、容錯和高可用性。相應地,大多數 servlet 容器支持某種形式的 HttpSession 復制,但是復制的機制、配置和時間是由實現決定的。