準則: 設計 J2EE 應用程式的狀態
這個準則討論 J2EE 應用程式的狀態管理設計機制。
關係
主要說明

簡介

有效管理應用程式狀態是設計分散式應用程式的一個重要主題。這個準則概述在 J2EE 應用程式中有關狀態管理的一些常見的設計考量和機制。

在專案的「詳述階段」,應該指出有關狀態管理的設計考量。軟體架構師在「分析與設計規範」活動:定義候選的架構的相關活動中,應該檢查狀態管理的一般方法。在 作業:架構分析期間,軟體架構師應該檢查應用程式的延展性和效能需求,決定必須採用什麼狀態管理技術,才能讓應用程式達到效能目標。在「詳述階段」期間,隨著應用程式逐漸修正,架構設計師需要在作業:指出設計機制中定義 J2EE 特定的設計和實作機制,以管理應用程式的狀態資訊。

根據概念:J2EE 部署配置的說明,J2EE 應用程式可以由分散在一個至許多實體層(機器)的多個邏輯層組成。簡短概述狀態管理的技術之後,這個準則的其餘各節將討論可在許多應用程式層使用的各種狀態管理設計和實作機制。

請注意,軟體架構師應該在工作成果:軟體架構文件載明已選取哪些機制,且應該在專案特有設計準則中提供這些機制的使用準則。

技術概觀

目前愈來愈流行建置分散式應用程式,以各種方式與網際網路互動。雖然網際網路的基礎在本質上為 Stateless,但建置任何類型的商業應用系統往往都需要管理狀態。假設有一個網際網路應用程式,使用者按一下從 page-a 至 page-b 的鏈結。處理 page-b 要求的應用程式不能再存取用來處理 page-a 的資訊。靜態網頁或許可以接受這種行為,但大多數商業應用系統都需要前一個處理程序的相關資訊。此時,J2EE 提供的狀態管理機制就可以派上用場。

暫時與持續狀態的比較

在深入探究狀態管理準則之前,必須先區別狀態資訊的類型。狀態資訊大致上可分為兩種:暫時(只存在應用程式有作用的這段時間)和持續(應用程式終止之後繼續存在)。

暫時狀態資訊存在的時間等於保存此資訊的實體存在的時間。例如,在普通的 Java 類別中儲存為欄位的狀態資訊。如果此類別所在的儲存區因任何理由終止,將會遺失狀態資訊,除非資料已抄寫至別處,例如備用伺服器。

持續狀態存在的時間等於用來保存狀態資訊的資料儲存庫存在的時間。持續狀態資訊通常儲存在檔案或資料庫中,在應用程式需要時才會載入。持續狀態資訊的任何變更必須寫回資料庫。持續資料儲存庫和應用程式所存取的資料,應該保持一致的完整性和可回復性。儲存在資料儲存庫中的資訊就是一種持續狀態,例如儲存在關聯式資料庫中。

階段作業狀態

Web 用戶端通常必須能夠發出多個瀏覽器要求、導覽各網頁,同時保留用戶端特定的資訊,例如購物車裡的商品。對此,Web 應用程式的作法是建立階段作業 ID,並在狀態資料與此階段作業 ID 之間建立關聯性。階段作業 ID 和關聯的狀態稱為階段作業狀態。

階段作業狀態是指用戶端和 Web 應用程式在一段短暫時間內(分鐘或小時,不是以天數計算)互動的相關資料。因此,階段作業狀態是暫短的資料,通常在一定的逾時期間之後就會刪除,以免耗用資源。

階段作業狀態可儲存在用戶端或伺服器上,稍後幾節將做說明。J2EE 平台特別為管理階段作業狀態提出幾種機制,因為這對於 Web 型應用程式很重要。

基本的持續性機制

以下是 Web 應用程式用來儲存狀態的常用機制。

Cookie

Cookie 是儲存在 Web 型用戶端的小型文字檔。伺服器可以將 Cookie 儲存在用戶端 後續的用戶端要求會將 Cookie 傳送給伺服器,讓伺服器存取 Cookie 中儲存的狀態資料。

Cookie 的一些問題如下:

  • 許多使用者認為 Cookie 會危害安全及/隱私,所以都會停用 Cookie。
  • Cookie 標頭的大小有限制,所以會限制儲存的資料量。
  • 有些通訊協定不支援 Cookie,例如「無線存取通訊協定 (WAP)」。
  • 如果用戶端從另一個位置登入(例如另一台機器),則無法使用另一個位置儲存的 Cookie。
  • 狀態資料必須能夠以字串值表示。

URL 重新編寫

「URL 重新編寫」是將階段作業狀態嵌入每一頁參照的 URL 中的一種機制。當 Web 伺服器產生要傳遞給用戶端的網頁時,就會將階段作業狀態編碼加入網頁的 URL 中。然後,當使用者按一下 URL 時,URL 中儲存的狀態資料會送回伺服器,讓伺服器重新建立階段作業環境。有一種類似的機制使用 HTML 隱藏欄位。這些機制的問題如下:

  • 特定階段作業中的所有網頁都必須由伺服器處理,否則伺服器會失去階段作業的線索。
  • 當用戶端關閉瀏覽器時,或經由手動鍵入或利用書籤連結至特定 URL 時,狀態不會保留下來。
  • 如同 Cookie 一樣,當用戶端從另一個位置登入時,狀態資料就不存在。
  • 如同 Cookie 一樣,狀態資料必須能夠以字串值表示。

純文字檔

純文字檔是維護持續狀態資訊的其中一項最簡單的方法。起始設定時會讀取純文字檔來建立起始狀態值。狀態每次變更時,必須重寫檔案來儲存狀態。在純文字檔中維護應用程式狀態的一些缺點如下:

  • 不利於應用程式的延展性,因為當應用程式狀態變數在更新和重新寫入純文字檔時,應用程式必須鎖定應用程式物件,以防止存取廣域資料。
  • 在大多數情況下,更新資料需要重寫整個檔案。
  • 純文字檔在發生錯誤時不一定能夠回復。

XML

在 XML 檔案中維護持續狀態資訊比使用純文字檔更好。相較於使用純文字檔,在 XML 檔案中維護應用程式狀態的一些優點如下:

  • XML 檔案提供純文字檔所欠缺的結構。
  • XML 檔案可透過標準的 API 來剖析。
  • XML 檔案通常較具可攜性。

資料庫

在資料庫中維護持續狀態資訊有最大的可回復性。 在資料庫中維護應用程式狀態的一些優點如下:

  • 表格的設計提供結構。
  • 更新應用程式變數時,不必重寫整個應用程式狀態。只需要重寫更新的資訊。
  • 經由協調應用程式狀態回復和正式作業資料庫的回復,可以保持一致性。
  • 在要求高可靠性的狀況下,可以聚集資料庫伺服器來形成叢集。

可透過「Java 資料庫連線功能 (JDBC)」API 來存取資料庫。JDBC 也可用來存取其他列表式資料來源(包括試算表)和純文字檔。

J2EE 特定機制

J2EE 平台提供特定的機制來管理狀態。這些都是高階的機制,可以配置來使用目前為止提出的一或多種基本的機制。

Servlet 環境

Servlet 可以利用 Servlet 環境來儲存適用於多個用戶端和用戶端階段作業的資料。

基本上,儲存在 Servlet 環境中的資料是 J2EE 應用程式的廣域變數。因此,使用應用程式狀態對應用程式設計有重大影響。軟體架構師在作業:指出設計機制時必須分解下列項目,判斷 Servlet 環境是否適當:

  • Servlet 環境可以保留在單一程序中,因此在多個伺服器之間不共用(叢集)。如果這不符合應用程式的延展性需求,架構設計師必須考慮將狀態儲存為階段作業狀態。  
  • Servlet 環境是程序記憶體的一部分,因此在程序終止時,通常不會保留下來。
  • 多個執行緒可以存取廣域資料。廣域資料的鎖定和同步化可能會影響應用程式的延展性。

HTTP 階段作業物件

Servlet 和 JSP 可以將特定用戶端階段作業相關的資料儲存在「HTTP 階段作業物件」中。如果將資料儲存在階段作業物件中,則階段作業資料應該如何讓多個伺服器使用,可能會有問題。有些供應商允許將用戶端要求遞送到相同的伺服器,這種作法稱為「伺服器親緣性」。

在處理用戶端要求時,伺服器上有「HTTP 階段作業物件」可用,但在各要求之間不一定會儲存在伺服器上。伺服器可以配置來使用前述任何基本的持續性機制,包括將階段作業狀態儲存在用戶端的 Cookie 中,或伺服器上的檔案或資料庫中。也可能允許跨伺服器將階段作業資料抄寫至記憶體中。

經由配置伺服器可選取機制 - 撰寫 JSP 和 Servlet 的程式碼與選取的機制無關,只需根據 Servlet 規格指定的 API 來存取階段作業物件。

Enterprise JavaBeans

Enterprise JavaBeans 包含高階機制來儲存狀態,這些機制以先前描述的低階機制為基礎,例如資料庫和檔案。Stateful Session Bean 用於儲存特定用戶端階段作業相關的資料,Entity Bean 用於儲存長期的資料。有關 EJB 儲存的狀態的討論,請參閱準則:Enterprise JavaBean (EJB)

設計階段作業狀態

Web 用戶端通常必須能夠發出多個瀏覽器要求、導覽各網頁,同時保留用戶端特定的資訊,例如購物車裡的商品。對此,Web 應用程式的作法是建立階段作業 ID,並在狀態資料與此階段作業 ID 之間建立關聯性。

階段作業 ID 本身採用一或兩種機制儲存在用戶端:

  • Cookie - 每一次要求時,用戶端瀏覽器將此 Cookie 傳送給伺服器,讓伺服器重新建立階段作業狀態。
  • URL 重新編寫 - 伺服器傳遞至用戶端的網頁中的 URL 會將階段作業 ID 編碼。當使用者按一下 URL 時,階段作業 ID 會傳送至伺服器,讓伺服器重新建立階段作業狀態。

伺服器會配置為使用選取的方法。Servlet 和 JSP 的程式碼撰寫可以不必考慮配置的方法。尤其應該以 HttpServletResponse.encodeURL() 方法將所有 URL 編碼。此方法會檢查是否啟用 URL 重新編寫,如果已啟用,則執行編碼。

階段作業 ID 相關的資料可以儲存在 JSP 和 Servlet 可存取的 HTTP 階段作業物件中,或儲存在 Session Bean 中。

階段作業 ID 和相關聯的資料應該設為逾時,才不會讓長時間未使用的階段作業資料無限期地耗用資源。架構設計師應該選取適當的逾時期間。

選取正確的機制

基於簡單性和效能的考量,架構設計師應該將階段作業狀態儲存在用戶端。由用戶端管理和儲存狀態時,伺服器就不必浪費資源來儲存狀態資訊或顧慮一致性。以用戶端來儲存狀態資訊的缺點是資訊在必要時就要送達伺服器,以致於出現網路延遲的問題。如果您不希望用戶端知道某些階段作業狀態資料,則可能也要考慮安全性的問題。在此情況下,可以選擇加密。

如果應用程式有大量的階段作業狀態,通常最好將此狀態儲存在伺服器上,因為伺服器通常較沒有大小和類型的限制。

通常,關於外觀呈現的階段作業狀態應該儲存在 HTTP 階段作業物件中,而 Stateful Session Bean 應該包含正確實作商業邏輯所需的狀態。應該避免狀態資料重複 - 而是將任何重複的狀態資料移入 HTTP 階段作業,視需要將此資料做為呼叫 Session Bean 方法的參數傳送至 Session Bean。

如果儲存在伺服器上的階段作業資料必須在伺服器節點故障時存留下來,請考慮利用機制來保存或抄寫階段作業資料。

設計持久的狀態

階段作業資料用於逾時的短暫用戶端資料。有些資料也可能需要保留更久的時間。

這種資料的正確機制視儲存的資料本質而定。Cookie、純文字檔、XML 檔案及資料庫都是可選擇的作法。以資料庫存取而言,Entity Bean 通常是最佳選擇。如需詳細資訊,請參閱準則:Entity Bean