在 IBM Bluemix 雲平臺上開發並部署您的下一個應用。緩存
開始您的試用安全
引言
在過去的差點兒整整十年中,人們編寫了很是多有關 Java™ Platform, Enterprise Edition (Java EE) 最佳實踐的內容。現在有十多本書籍和數以百計(可能不少其它)的文章,提供了關於應該怎樣編寫 Java EE 應用程序的看法。
其實,這方面的參考資料如此之多,並且這些參考資料之間每每還存在着一些矛盾的建議,以致於在這些混雜的內容中進行學習自己也成爲了採用 Java EE 的障礙。
所以。爲了給剛進入這個領域的客戶提供一些簡單的指導,咱們彙編了這個最重要的最佳實踐列表,當中包含咱們以爲最重要和最有效的 Java EE 最佳實踐。遺憾的是,咱們沒法僅在 10 大最佳實踐中描寫敘述所有需要介紹的內容。所以。爲了不遺漏關鍵的最佳實踐和尊重 Java EE 的發展,咱們的列表中包括了「19 大」關鍵的 Java EE 最佳實踐。
最重要的最佳實踐
您可以點擊例如如下連接,當即下載 WebSphere Application Server 軟件 V7 版本號,體驗其爲您帶來的新特性及新功能。
- WebSphere Application Server for Developers V7(免費產品)
- WebSphere Application Server V7 試用版
- WebSphere Application Server Express V7 試用版
- WebSphere Application Server Hypervisor Edition V7 試用版(虛擬映像)
不少其它關於 WebSphere Application Server 的技術資源,請參考:
- WebSphere Application Server 產品專題:爲您提供了 WebSphere Application Server 相關的文章、教程、多媒體課堂等最新技術資源。
- WebSphere Application Server V7 專題:爲您總結了與 WAS V7 相關最新的內容和資源,當中包含入門介紹及開發技巧、配置與管理、遷移、監控與測試等。
- 始終使用 MVC 框架。
- 不要作反覆的工做。
- 在每一層都應用本身主動單元測試和測試管理。
- 依照規範來進行開發,而不是依照顧用server來進行開發。
- 從一開始就計劃使用 Java EE 安全性。
- 建立您所知道的。
- 當使用 EJB 組件時,始終使用會話 Facade。
- 使用無狀態會話 Bean,而不是有狀態會話 Bean。
- 使用容器管理的事務。
- 將 JSP 做爲表示層的首選。
- 當使用 HttpSession 時,儘可能僅僅將當前事務所需要的狀態保存當中。其它內容不要保存在 HttpSession 中。
- 充分利用應用server中不需要改動代碼的特性。
- 充分利用現有的環境。
- 充分利用應用server環境所提供的服務質量。
- 充分利用 Java EE,不要欺騙。
- 安排進行版本號更新。
- 在代碼中所有關鍵的地方,使用標準的日誌框架記錄程序的狀態。
- 在完畢對應的任務後。請始終進行清理。
- 在開發和測試過程當中遵循嚴格的程序。
1. 始終使用 MVC 框架。
將業務邏輯(Java Bean 和 EJB 組件)從控制器邏輯(Servlet/Struts 操做)和表示邏輯(JSP、XML/XSLT)中清晰地分離出來。良好的分層可以帶來不少優勢。
這項實踐很重要。以至沒有其它最佳實踐可以與其相提並論。
對於良好的 Java EE 應用程序設計而言。模型-視圖-控制器 (MVC) 是相當重要的。它將程序的任務簡單地分爲如下幾個部分:
- 負責業務邏輯的部分(模型,一般使用 Enterprise JavaBeans™ 或傳統 Java 對象來實現)。
- 負責用戶接口表示的部分(視圖)。
- 負責應用程序導航的部分(控制器,一般使用 Java Servlet 或類 Struts 控制器這樣相關的類來實現)。
對於 Java EE。有不少關於這個主題的優秀評論。咱們特別推薦感興趣的讀者可以參考 [Fowler] 或者 [Brown](請參見參考資料部分)的評論,以便全面和深刻地瞭解相關內容。
假設不遵循主要的 MVC 體系結構。在開發過程當中就會出現不少的問題。最多見的問題是。將過多的任務放到該體系結構的視圖部分中。可能存在使用 JSP 標記來運行數據庫訪問,或者在 JSP 中進行應用程序的流程控制。這在小規模的應用程序中是比較常見的,但是。隨着後期的開發。這樣作將會帶來問題,因爲 JSP 逐步變得愈來愈難以維護和調試。
相似地,咱們也經常看到將視圖層構建到業務邏輯的狀況。好比,一個常見的問題就是將在構建視圖時使用的 XML 解析技術直接應用到業務層。
業務層應該對業務對象進行操做,而不是對與視圖相關的特定數據表示進行操做。
然而。只使用適當的組件沒法實現應用程序的正確分層。
咱們常常見到一些應用程序包括 Servlet、JSP 和 EJB 組件所有這三項,然而,其基本的業務邏輯倒是在 Servlet 層實現的,或者應用程序導航是在 JSP 中處理的。您必須對代碼進行嚴格的檢查和重構,以確保僅在模型層中處理業務邏輯。在控制器層中進行應用程序導航,而視圖應該只關心怎樣將模型對象呈現爲合適的 HTML 和 Javascript™。
本文中這項建議的涵義應該比原始版本號中的更加清楚。用戶接口技術不斷地發生着變化,將業務邏輯關聯於用戶接口,會使得對接口的更改影響到現有的系統。幾年以前。Web 應用程序用戶接口開發者可能從 Servlet 和 JSP、Struts 和 XML/XSL 轉換中進行選擇。在那之後。Tiles 和 Faces 很流行,而現在,AJAX 大行其道。假設每當首選的用戶接口技術發生了更改就要又一次開發應用程序的核心業務邏輯,那麼就糟透了。
2. 不要作反覆的工做。
使用常見的、通過證明的框架。如 Apache Struts、JavaServer Faces 和 Eclipse RCP。使用通過證明的模式。
回到咱們開始幫助客戶使用剛出現的 Java EE 標準的時候,咱們發現(和更多人同樣)。經過直接使用基礎的 Servlet 和 JSP 規範構建 UI 應用程序來開發用戶接口開發框架。可以極大地提升開發者工做效率。
所以。不少公司開發了他們本身的 UI 框架,這些框架可以簡化接口開發的任務。
隨着開放源代碼的框架(如 Apache Struts)的出現 [Brown]。咱們相信。可以本身主動地和高速地轉換到這些新的框架。
咱們以爲,使用開放源代碼社區支持的框架很是適合於開發者,並且這些框架很是快獲得了普遍承認。不只可用於新的開發,還可以改動現有的應用程序。
但使人感到奇怪的是,事實並非如此。咱們仍能夠看到不少公司在維護或甚至開發新的用戶接口框架,而這些框架的功能與 Struts 或者 JSF 是全然一樣的。
之因此會出現這樣的狀況,有不少緣由:機構惰性。「非我發明」症。不瞭解更改現有代碼的優勢、或者甚至傲慢地以爲能夠比開放源代碼開發者的特定框架作得更好。
然而。這些緣由都已通過時了,不能夠成爲不採用標準框架的藉口。Struts 和 JSF 不只在 Java 社區中獲得了普遍承認。而且還受到 WebSphere 執行時和 Rational® 工具套件的全面支持。相同地,在富client領域中,Eclipse RCP(富client平臺,Rich Client Platform)得到了普遍的承認。可用於構建獨立的富client。雖然不是 Java EE 標準中的一部分。但這些框架現在已成爲 Java EE 社區的一部分。而且理應如此。
對於那些因爲傲慢而不肯使用現成的 UI 框架的人,應該閱讀 [Alur] 和 [Fowler] 中介紹的內容。這兩本書具體地描寫敘述了企業 Java 應用程序中最常用的可重用模式。
從相似於會話 Facade 這樣簡單的模式(將在後面的建議中討論)到相似於 Fowler 持久性模式(不少開放源代碼的持久性框架對其進行了實現)這樣比較複雜的模式。當中的內容體現了 Java 前輩們所積累的智慧。那些不能吸收教訓的人必然會重蹈覆轍(假設他們很幸運。能夠在第一次失敗以後得到重來一次的機會)。他們不得不向哲學家 Santayana 說抱歉。
3. 在應用程序的每一層都使用本身主動單元測試和測試管理。
不要僅僅是測試您的圖形用戶界面(GUI)。分層的測試使得調試和維護工做變得極其簡單。
在過去的幾年中,在方法學領域有了至關大的革新。好比新出現的被稱爲 Agile(如參考資料部分中的 SCRUM [Schwaber] 和極限編程 [Beck1])的輕量級方法現在已經獲得了很是廣泛的應用。差點兒所有的這些方法中的一個共同特徵是它們都提倡使用本身主動的測試工具。這些工具可以幫助開發者用更少的時間進行迴歸測試,並可以幫助他們避免因爲不充分的迴歸測試形成的錯誤,所以可以用來提升程序猿的工做效率。
實際上,另外一種被稱爲 Test-First Development [Beck2] 的方法,這樣的方法甚至提倡在開發實際的代碼以前就先編寫單元測試。
然而。在您測試代碼以前,您需要將代碼切割成一些可測試的片段。一個「大泥球」是難以測試的。因爲它不是僅僅實現一個簡單的易於識別的功能。假設您的每個代碼片段實現多個方面的功能。將難以測試當中的每個部分以保證其正確性。
MVC 體系結構(以及 Java EE 中的 MVC 實現)的一個長處就是元素的組件化能夠(實際上,至關的簡單)對您的應用程序進行單元測試。所以,您能夠方便地對實體 Bean、會話 Bean 以及 JSP 獨立編寫測試用例。而沒必要考慮其它代碼。現在有不少用於 Java EE 測試的框架和工具。這些框架及工具使得這一過程更加簡單。好比。JUnit(是一種由 junit.org 開發的開放源碼工具)和 Cactus(由 Apache 協會開發的開放源碼工具)對於測試 Java EE 組件都很實用。[Hightower] 具體探討了怎樣在 Java EE 中使用這些工具。
雖然所有這些詳述瞭如何完全地測試您的應用程序。但是咱們仍然看到一些人以爲僅僅要他們測試了 GUI(多是基於 Web 的 GUI,或者是獨立的 Java 應用程序),則他們就全面地測試了整個應用程序。僅進行 GUI 測試是不夠的。
GUI 測試很是難達到全面的測試,有下面幾種緣由。
- 使用 GUI 測試很是難完全地測試到系統的每一條路徑,GUI 不過影響系統的一種方式。可能存在後臺運算、腳本和各類各樣的其它訪問點,這也需要進行測試。然而,它們一般並不具備 GUI。
- GUI 級的測試是一種很粗粒度的測試。這樣的測試僅僅是在宏觀水平上測試系統的行爲,這意味着一旦發現存在問題,則與此問題相關的整個子系統都要進行檢查,這使得找出錯誤將是很困難的事情。
- GUI 測試一般僅僅有在整個開發週期的後期才幹很是好地獲得測試,這是因爲僅僅有這那個時候 GUI 才獲得完整的定義。
這意味着僅僅有在後期纔可能發現潛在的錯誤。
- 通常的開發者可能沒有本身主動的 GUI 測試工具。所以。當一個開發者對代碼進行更改時,沒有一種簡單的方法來又一次測試受到影響的子系統。這實際上不利於進行良好的測試。
假設開發者具備本身主動的代碼級單元測試工具,開發者就行很是easy地執行這些工具以確保所作的更改不會破壞已經存在的功能。
- 假設加入了本身主動構建功能,則在本身主動構建過程當中加入一個本身主動的單元測試工具是很easy的事情。當完畢這些設置之後。整個系統就可以有規律地進行重建。並且迴歸測試差點兒不需要人的參與。
另外,咱們必須強調。使用 EJB 和 Web 服務進行分佈式的、基於組件的開發使得測試單個組件變得很必要。假設沒有「GUI」需要測試,您就必須進行低級(lower-level)測試。最好以這樣的方式開始測試,免得當您將分佈式的組件或 Web 服務做爲您的應用程序的一部分時,您不得不花費心思又一次進行測試。
總之,經過使用本身主動的單元測試,能夠很是快地發現系統的缺陷,並且也易於發現這些缺陷,使得測試工做變得更加系統化,所以整體的質量也得以提升。
4. 依照規範來進行開發,而不是依照顧用server來進行開發。
要將規範熟記於心,假設要背離規範。需通過慎密的考慮後才幹夠這樣作。這是因爲當您背離規則的時候,您所作的事情每每並不是您應該作的事情。
當您要背離 Java EE 贊成您作的事情的時候,這很是easy讓使您遭受不幸。咱們發現有一些開發者鑽研一些 Java EE 贊成以外的東西,他們以爲這樣作可以「略微」改善 Java EE 的性能,而他們終於僅僅會發現這樣作會引發嚴重的性能問題,或者在之後的移植(從一個廠商到還有一個廠商。或者是更常見的從一個版本號到還有一個版本號)中會出現故障。實際上。這樣的移植問題是如此嚴重,以至 [Beaton] 將此原則稱爲移植工做的基本最佳實踐。
現在有好幾個地方假設不直接使用 Java EE 提供的方法確定會產生問題。
一個常見的樣例就是開發者經過使用 JAAS 模塊來替代 Java EE 安全性,而不是使用內置的遵循規範的應用server機制來進行驗證和受權。要注意不要脫離 Java EE 規範提供的驗證機制。假設脫離了此規範,這將是系統存在安全漏洞以及廠商兼容性問題的主要緣由。相似地,要使用 Servlet 和 EJB 規範提供的受權機制,並且假設您要偏離這些規範的話。要確保使用規範定義的 API(好比 getCallerPrincipal())做爲實現的基礎。經過這樣的方式,您將能夠利用廠商提供的強安全性基礎設施,當中。業務要求需要支持複雜的受權規則。
(有關受權的更具體內容。請參見 [Ilechko]。
)
其它常見的問題包含使用不遵循 Java EE 規範的持久性機制(這使得事務管理變得困難)、在Java EE程序中使用不適當的 J2SE 方法(好比線程或 singleton),以及使用您本身的方法解決程序到程序(program-to-program)的通訊,而不是使用 Java EE 內在支持的機制(好比 JCA、JMS 或 Web 服務)。當您將一個遵循 Java EE 的server移植到其它的server上。或者移植到一樣server的新版本號上,上述的設計選擇將會形成無數的問題。使用 Java EE 以外的元素,通常會致使一些細微的可移植性問題。惟一要背離規範的狀況是。當一個問題在規範的範圍內沒法解決的時候。好比,安排運行定時的業務邏輯在 EJB2.1 出現以前是一個問題。
在相似這種狀況下,咱們建議當有廠商提供的解決方式時就使用廠商提供的解決方式(好比 WebSphere Application Server Enterprise 中的 Scheduler 工具)。而在沒有廠商提供的解決方式時就使用第三方提供的工具。
固然。現在的 EJB 規範提供了基於時間的函數,因此咱們鼓舞使用這些標準接口。
假設使用廠商提供的解決方式,應用程序的維護以及將其移植到新的規範版本號將是廠商的問題,而不是您的問題。
最後,要注意不要太早地採用新技術。太過於熱衷採用尚未集成到 Java EE 規範的其它部分或者尚未集成到廠商的產品中的技術常會帶來災難性的後果。支持是關鍵的——假設您的廠商不直接支持某種特定的技術,那麼您在採用此技術時就應該很是慎重。
有些人(尤爲是開發者)過度關注於簡化開發過程,忽略了依賴大量本組織以外開發的代碼的長期後果,而供應商並不支持這些代碼。咱們發現,不少項目團隊沉迷於新技術(好比最新的開放源碼框架)。並非常快地依賴於它。卻沒有考慮它對業務帶來的實際代價。坦白地說,對於使用您的供應商所提供的產品以外的不論什麼技術的決策。都應該由企業組織結構中的各個部門、業務團隊和法律團隊(或您的環境中的等同機構)細緻地進行評審。這與正常的產品購買決策全然一樣。畢竟,咱們中的大多數人是在解決業務問題,而不是推動技術的發展。
5. 從一開始就計劃使用 Java EE 安全性。
啓用 WebSphere 安全性。
這使您的 EJB 和 URL 至少可以讓所有受權用戶訪問。
不要問爲何——照着作就是了。
在與咱們合做的客戶中。一開始就打算啓用 WebSphere Java EE 安全性的顧客是不多的,這一點一直讓咱們感到驚訝。
據咱們預計大約僅僅有 50% 的顧客一開始就打算使用此特性。
好比,咱們曾與一些大型的金融機構(銀行、代理等等)合做過,他們也沒有打算啓用安全性。幸運的是,這樣的問題在部署以前的檢查時就得以解決。
不使用 Java EE 安全性是件危急的事情。若是您的應用程序需要安全性(差點兒所有的應用程序都需要),敢打賭您的開發者能夠構建出本身的安全性基礎設施,其比您從 Java EE 廠商那裏買來的更好。這可不是個好的賭博遊戲。
爲分佈式的應用程序提供安全性是異常困難的。
好比,您需要使用網絡安全加密令牌控制對 EJB 的訪問。以咱們的經驗看來,大多數本身構建的安全性基礎設施是不安全的,並且有重大的缺陷,這使產品系統極其脆弱。
(有關更具體的信息,請參考 [Barcia] 的第 18 章。
)
一些不使用 Java EE 安全性的理由包含:操心性能的降低,相信其它的安全性(好比 IBM Tivoli® Access Manager 和 Netegrity SiteMinder)能夠代替 Java EE 安全性,或者是不知道 WebSphere Application Server 安全特性及功能。不要陷入這些陷阱之中。
尤爲是,雖然像 Tivoli Access Manager 這種產品能夠提供優秀的安全特性,但是隻其自身不可能保護整個 Java EE 應用程序。這些產品必須與 Java EE 應用server聯合起來纔可能全面地保護您的系統。
其它一種常見的不使用 Java EE 安全性的緣由是,基於角色的模型沒有提供足夠的粒度訪問控制以知足複雜的業務規則。雖然事實是這種,但這也不該該成爲不使用 Java EE 安全性的理由。
相反地。應該將 Java EE 驗證及 Java EE 角色與特定的擴展規則結合起來。
假設複雜的業務規則需要作出安全性決策。那就編寫對應的代碼。其安全性決策要基於可以直接使用的以及可靠的 Java EE 驗證信息(用戶 ID 和角色)。(有關受權的更具體的信息,請參見 [Ilechko]。)
6. 建立您所知道的。
重複的開發工做將使您能夠逐漸地掌握所有的 Java EE 模塊。要從建立小而簡單的模塊開始而不是從一開始就當即涉及到所有的模塊。
咱們必須認可 Java EE 是龐大的體系。假設一個開發團隊僅僅是開始使用 Java EE,這將很是難一會兒就能掌握它。在 Java EE 中有太多的概念和 API 需要掌握。在這樣的狀況下。成功掌握 Java EE 的關鍵是從簡單的步驟開始作起。
這樣的方法可以經過在您的應用程序中建立小而簡單的模塊來獲得最好的實現。
假設一個開發團隊經過建立一個簡單的域模型以及後端的持久性機制(或許使用的是 JDBC),並且對其進行了完整的測試。這會加強他們的自信心,因而他們會使用該域模型去掌握使用 Servlet 和 JSP 的前端開發。
假設一個開發團隊發現有必要使用 EJB。他們也會相似地開始在容器管理的持久性 EJB 組件之上使用簡單的會話 Facade。或者使用基於 JDBC 的數據訪問對象(JDBC-based Data Access Objects,DAO)。而不是跳過這些去使用更加複雜的構造(好比消息驅動的 Bean 和 JMS)。
這樣的方法並不是什麼新方法。但是很是少有開發團隊以這樣的方式來培養他們的技能。相反地,多數開發團隊由於嘗試當即就構建所有的模塊,同一時候涉及 MVC 中的視圖層、模型層和控制器層,這樣作的結果是他們每每會陷入進度的壓力之中。他們應該考慮一些敏捷(Agile)開發方法,好比極限編程(XP),這樣的開發方法採用一種增量學習及開發方法。在 XP 中有一種稱爲 ModelFirst [Wiki] 的過程,這個過程涉及到首先構建域模型做爲一種機制來組織和實現用戶場景。
基本說來。您要構建域模型做爲您要實現的用戶場景的首要部分,而後在域模型之上構建一個用戶界面(UI)做爲用戶場景實現的結果。這樣的方法很是適合讓一個開發團隊一次僅僅學到一種技術。而不是讓他們同一時候面對很是多種狀況(或者讓他們讀很是多書)。這會令他們崩潰的。
還有。對每個應用程序層反覆的開發可能會包括一些適當的模式及最佳實踐。假設您從應用程序的底層開始應用一些模式(如數據訪問對象和會話 Facade)。您就不該該在您的JSP和其它視圖對象中使用域邏輯。
最後。當您開發一些簡單的模塊時,在開始的初期就可以對您的應用程序進行性能測試。假設直到應用程序開發的後期才進行性能測試的話,這每每會出現災難性的後果,正如 [Joines] 所述。
7. 當使用 EJB 組件時。始終使用會話 Facade。
在體系結構合適的狀況下,使用本地 EJB。
當使用 EJB 組件時。使用會話 Facade 是一個確認無疑的最佳實踐。
實際上。這個通用的實踐被普遍地應用到不論什麼分佈式技術中。包括 CORBA、EJB 和 DCOM。
從根本上講,您的應用程序的分佈「交叉區域」越是底層化,對小塊的數據由於屢次反覆的網絡中繼形成的時間消耗就越少。要達到這個目的的方法是。建立大粒度的 Facades 對象。這個對象包括邏輯子系統。於是可以經過一個方法調用就可以完畢一些實用的業務功能。這樣的方法不但可以下降網絡開銷。而且在 EJB 內部經過爲整個業務功能建立一個事務環境也可以大大地下降對數據庫的訪問次數。[Alur] 對這樣的模式進行了規範的表示。[Fowler](並且包含除 EJB 以外的狀況)和 [Marinescu] 也對其進行了描寫敘述(請參見參考資料)。細心的讀者會發現。這實際上正是面向服務的體系結構 (SOA) 中的核心原則之中的一個。
EJB 本地接口(從 EJB 2.0 規範開始使用)爲共存的 EJB 提供了性能優化方法。
本地接口必須被您的應用程序顯式地進行訪問,這需要代碼的改變和防止之後配置 EJB 時需要應用程序的改變。
假設您肯定 EJB 調用始終是本地的,那麼可以充分利用本地 EJB 的優化。然而,會話 Facade 自己的實現(典型樣例如無狀態會話 Bean)應該設計爲遠程接口。經過這樣的方式,其它的client可以遠程地使用 EJB 自己。而不會破壞現有的業務邏輯。因爲 EJB 可以同一時候具備本地和遠程接口,因此這是全然可以實現的。
爲了性能的優化,可以將一個本地接口加入到會話 Facade。這樣作利用了這樣一個事實,在大多數狀況下(至少在 Web 應用程序中),您的 EJB client和 EJB 會共同存在於同一個 Java 虛擬機(JVM)中。第二種狀況是,假設會話 Facade 在本地被調用,可以使用 Java EE 應用server配置優化(configuration optimizations),好比 WebSphere 中的「No Local Copies」。
然而,您必須注意到這些可供選擇的方案會將交互方法從按值傳遞(pass-by-value)改變爲按引用傳遞(pass-by-reference)。這可能會在您的代碼中產生很是微妙的錯誤。最好使用本地 EJB,因爲對於每個 Bean 而言。其行爲是可以控制的。而不會影響到整個應用server。
假設在您的會話 Facade 中使用遠程接口(而不是本地接口)。您也可以將相同的會話 Facade 在 Java EE 1.4 中以兼容的方式做爲 Web 服務來配置。(這是因爲 JSR 109,Java EE 1.4 中的 Web 服務部署部分。要求使用無狀態會話 Bean 的遠程接口做爲 EJB Web 服務和 EJB 實現的接口。)這樣作是值得的。因爲這樣作可以爲您的業務邏輯添加client類型的數量。
8. 使用無狀態會話 Bean。而不是有狀態會話 Bean。
這樣作可以使您的系統更經得起故障轉移。使用 HttpSession 存儲和用戶相關的狀態。
以咱們的觀點來看,有狀態會話 Bean 的概念已通過時了。
假設您細緻對其考慮一下。一個有狀態會話 Bean 實際上與一個 CORBA 對象在體系結構上是全然一樣的,無非就是一個對象實例綁定到一個server,並且依賴於server來管理其生命週期。假設server關閉了。這樣的對象也就不存在。那麼這個 Bean 的client的信息也就不存在。
Java EE 應用server爲有狀態會話 Bean 提供的故障轉移能夠解決一些問題,但是有狀態的解決方式沒有無狀態的解決方式易於擴展。好比。在 WebSphere Application Server 中。對無狀態會話 Bean 的請求。是經過對部署無狀態會話的成員集羣進行平衡載入來實現。相反地。Java EE 應用server不能對有狀態 Bean 的請求進行平衡載入。
這意味着您的集羣中的server的載入過程會是不均衡的。此外,使用有狀態會話 Bean 將會再加入一些狀態到您的應用server上。這也是很差的作法。
有狀態會話 Bean 添加了系統的複雜性,並且在出現問題的狀況下使問題變得複雜化。建立健壯的分佈式系統的一個關鍵原則是儘可能使用無狀態行爲。
所以。咱們建議對大多數應用程序使用無狀態會話 Bean 方法。不論什麼在處理時需要使用的與用戶相關的狀態應該以參數的形式傳送到 EJB 的方法中(並且經過使用一種機制如 HttpSession 來存儲它)或者從持久性的後端存儲(好比經過使用實體 Bean)做爲 EJB 事務的一部分來進行檢索。在合適的狀況下。這個信息可以緩存到內存中。但是要注意在分佈式的環境中保存這樣的緩存所潛在的挑戰性。緩存很適合於僅僅讀數據。
總之,您要確保從一開始就要考慮到可擴展性。
檢查設計中的所有設想,並且考慮到當您的應用程序要在多個server上執行時。是否也可以正常執行。檢查設計中所有的若是,推斷若是您的應用程序執行於多個server之上。它們是否依舊成立。這個規則不但適合上述狀況的應用程序代碼,也適用於如 MBean 和其它管理接口的狀況。
避免使用有狀態性不只僅是對 IBM/WebSphere 的建議,這是一個主要的 Java EE 設計原則。
請參見 [Jewell] 的 Tyler Jewell 對有狀態 Bean 的批評,其觀點和上述的觀點是一樣的。
9. 使用容器管理的事務。
學習一下 Java EE 中的兩階段提交事務,並且使用這樣的方式。而不是開發您本身的事務管理。
容器在事務優化方面差點兒老是比較好的。
使用容器管理的事務(CMT)提供了兩個關鍵的優點(假設沒有容器支持這差點兒是不可能的):可組合的工做單元和健壯的事務行爲。
假設您的應用程序代碼顯式地使用了開始和結束事務(或許使用 javax.jts.UserTransaction 或者甚至是本地資源事務),而未來的要求需要組合模塊(或許會是代碼重構的一部分),這樣的狀況下每每需要改變事務代碼。
好比。假設模塊 A 開始了一個數據庫事務,更新數據庫。隨後提交事務,並且有模塊 B 作出相同的處理,請考慮一下當您在模塊 C 中嘗試使用上述兩個模塊,會出現什麼狀況呢?現在,模塊 C 正在運行一個邏輯動做,而這個動做實際上將調用兩個獨立的事務。假設模塊 B 在運行中失敗了,而模塊 A 的事務仍然能被提交。
這是咱們所不但願出現的行爲。
假設,相反地,模塊 A 和模塊 B 都使用 CMT 的話,模塊 C 也可以開始一個 CMT(一般經過配置描寫敘述符)。並且在模塊 A 和模塊 B 中的事務將是同一個事務的隱含部分。這樣就再也不需要重寫複雜的代碼了。
假設您的應用程序在同一個操做中需要訪問多種資源。您就要使用兩階段提交事務。好比,假設從 JMS 隊列中刪除一個消息,並且隨後更新基於這條消息的紀錄。這時,要保證這兩個操做都會運行或都不會運行就變得尤其重要。
假設一條消息已經從隊列中被刪除,而系統沒有更新與此消息相關的數據庫中的記錄。那麼這樣的系統是不一致的。一些嚴重的客戶及商業糾紛源自不一致的狀態。
咱們時常看到一些客戶應用程序試圖實現他們本身的解決方式。或許會經過應用程序的代碼在數據庫更新失敗的時候「撤銷」對隊列的操做。咱們不提倡這樣作。
這樣的實現要比您最初的想象複雜得多,並且還有更多的狀況(想象一下假設應用程序在運行此操做的過程當中忽然崩潰的狀況)。做爲替代的方式,應該使用兩階段提交事務。
假設您使用 CMT。並且在單一的 CMT 中訪問兩階段提交的資源(好比 JMS 和大多數數據庫),WebSphere 將會處理所有的複雜工做。它將確保整個事務被運行或者都不被運行,包含系統崩潰、數據庫崩潰或其它的狀況。事實上現在事務日誌中保存着事務狀態。
當應用程序訪問多種資源的時候。咱們怎麼強調使用 CMT 事務的必要性都不爲過。假設您所訪問的資源不支持兩階段提交,那麼您固然就沒有別的選擇了,僅僅能使用一種比較複雜的方法,但是您應該儘可能避免這樣的狀況。
10. 將 JSP 做爲表示層技術的首選。
僅僅有在需要多種表示輸出類型,並且輸出類型被單一的控制器及後端支持時才使用 XML/XSLT。
咱們常聽到一些爭論說。爲何您選擇 XML/XSLT 而不是 JSP 做爲表示層技術,因爲 JSP「贊成您將模型和視圖混合在一塊兒」,而 XML/XSLT 不會有這樣的問題。
遺憾的是,這樣的觀點並不全然正確。或者至少不像白與黑那樣分的清楚。實際上。XSL 和 XPath 是編程語言。其實。XSL 是圖靈完備的(Turing-complete),雖然它不符合大多數人定義的編程語言。因爲它是基於規則的,並且不具有程序猿習慣的控制工具。
問題是既然給予了這樣的靈活性,開發者就會利用這樣的靈活性。
雖然每個人都認同 JSP 使開發者easy在視圖中增長「相似模型」的行爲,而實際上。在 XSL 中也有可能作出一些相同的事情。雖然從 XSL 中進行訪問數據庫這樣的事情會很困難,但是咱們之前見到過一些異常複雜的 XSLT 樣式表運行復雜的轉換。這其實是模型代碼。
然而,應該選擇 JSP 做爲首選的表示技術的最主要的緣由是。JSP 是現在支持最普遍的、也是最被普遍理解的 Java EE 視圖技術。而隨着本身定義標記庫、JSTL 和 JSP2.0 的新特性的引入,建立 JSP 變得更加easy。並且不需要不論什麼 Java 代碼,以及可以將模型和視圖清晰地分離開。在一些開發環境中(如 IBM Rational Application Developer)增長了對 JSP(包含對調試的支持)的強大支持,並且不少開發者發現使用 JSP 進行開發要比使用 XSL 更加簡單,主要是因爲 JSP 是基於例程的。而不是基於規則的。
雖然 Rational Application Developer 支持 XSL 的開發。但一些支持 JSP 的圖形設計工具及其它特徵(尤爲在 JSF 這種框架下)使得開發者可以以所見即所得的方式進行 JSP 的開發,而使用 XSL 有時不easy作到。
然而,這並不表示您毫不 應該使用 XSL。在一些狀況下,XSL 能夠表示一組固定的數據。並且能夠基於不一樣的樣式表(請參見 [Fowler])來以不一樣的方式顯示這些數據的能力是顯示視圖的最佳解決方式。
然而,這僅僅是一種特殊的狀況。而不是通用的規則。
假設您僅僅是生成 HTML 來表達每一個頁面,那麼在大多數狀況下,XSL 是一種沒必要要的技術。並且。它給您的開發者所帶來的問題遠比它所能解決的問題多。
11. 當使用 HttpSession 時,儘可能僅僅將當前事務所需要的狀態保存在當中。其它內容不要保存在 HttpSession 中。
啓用會話持久性。
HttpSessions 對於存儲應用程序狀態信息是很實用的。其 API 易於使用和理解。
遺憾的是,開發者常常遺忘了 HttpSession 的目的——用來保持暫時的用戶狀態。它不是隨意的數據緩存。咱們已經見到過太多的系統爲每個用戶的會話放入了大量的數據(達到兆字節)。假設同一時候有 1000 個登陸系統的用戶,每個用戶擁有 1MB 的會話數據,那麼就需要 1G 或者不少其它的內存用於這些會話。
保持這些 HTTP 會話數據較小。
否則的話,您的應用程序的性能將會降低。一個大約比較合適的數據量應該是每個用戶的會話數據在 2K-4K 之間。
這不是一個硬性的規則。
8K 仍然沒有問題,但是顯然會比 2K 時的速度要慢。必定要注意,不要使 HttpSession 變成數據堆積的場所。
一個常見的問題是使用 HttpSession 緩存一些很是easy再建立的信息。假設有必要的話。由於會話是持久性的,進行沒必要要的序列化以及寫入數據是一種很是奢侈的決定。
相反地,應該使用內存中的哈希表來緩存數據。並且在會話中保存一個對此數據進行引用的鍵。這樣,假設不能成功登陸到另外的應用server的話,就可以又一次建立數據。(有關更具體的信息,請參見 [Brown2]。)
當談及會話持久性時。不要忘記要啓用這項功能。假設您沒有啓用會話持久性,或者server因爲某種緣由中止了(server故障或正常的維護),則所有此應用server的當前用戶的會話將會丟失。
這是件使人很掃興的事情。用戶不得不又一次登陸,並且又一次作一些他們之前已經作過的事情。相反地。假設啓用了會話持久性,WebSphere 會本身主動將用戶(以及他們的會話)移到另一個應用server上去。用戶甚至不知道發生了這種事情。咱們之前見到過一些產品系統。因爲本地代碼中存在使人難以忍受的錯誤(不是 IBM 的代碼!
)而經常崩潰,在這種狀況下,上述功能仍然可以執行良好。
12. 充分利用應用server中不需要改動代碼的特性。
使用某些特性(如 WebSphere Application Server 緩存和 Prepared Statement 緩存)可以極大地提升性能,並且使得開銷最小。
前面的最佳實踐 4 清楚地描寫敘述了這樣一種案例,即關於爲何應該慎重的使用可能改動代碼的應用server特定的特性。它使得難以實現可移植性。並且可能給版本號的遷移帶來困難。然而,特別是在 WebSphere Application Server 中。有一套應用server特定的特性,您可以並且應該充分地利用它們,因爲它們不會改動您的代碼。
您應該依照規範來編寫代碼,但假設您瞭解這些特性以及怎樣正確地使用它們,那麼您就可以利用它們顯著地改善性能。
做爲這個最佳實踐的一個演示樣例,在 WebSphere Application Server 中。您應該開啓動態緩存,並且使用 Servlet 緩存。系統性能可以獲得很是大的提升。而開銷是最小的。並且不影響編程模型。經過緩存來提升性能的優勢是衆所周知的事情。遺憾的是,當前的 Java EE 規範沒有包含一種用於 Servlet/JSP 緩存的機制。然而,WebSphere 提供了對頁面以及片段緩存的支持。這樣的支持是經過其動態緩存功能來實現的,並且不需要相應用程序做出不論什麼改變。其緩存的策略是聲明性的。並且其配置是經過 XML 配置描寫敘述符來實現的。所以。您的應用程序不會受到影響,並保持與 Java EE 規範的兼容性和移植性。同一時候還從 WebSphere 的 Servlet 及 JSP 的緩存機制中獲得性能的優化。
從 Servet 及 JSP 的動態緩存機制獲得的性能的提升是顯而易見的,這取決於應用程序的特性。Cox 和 Martin [Cox] 指出,對一個現有的 RDF(資源描寫敘述格式)網站摘要 (RSS) Servlet 使用動態緩存時,其性能可以提升 10%。
請注意這個實驗僅僅涉及到一個簡單的 Servlet。這個性能的增加量可能並不能反映一個複雜的應用程序。
爲了不少其它地提升性能,將 WebSphere Servlet/JSP 結果緩存與 WebSphere 插件 ESI Fragment 處理器、IBM HTTP Server Fast Response Cache Accelerator (FRCA) 和 Edge Server 緩存功能集成在一塊兒。對於繁重的基於讀取的工做負荷,經過使用這些功能可以獲得不少額外的優勢。(請參見參考資料的 [Willenborg] 和 [Bakalova] 中描寫敘述的性能的提升。)
做爲該原則的還有一個演示樣例(咱們常常發現客戶不使用它,不過因爲他們根本不知道它的存在)。在編寫 JDBC 代碼時可以利用 WebSphere Prepared Statement Cache。
在缺省狀況下。當您在 WebSphere Application Server 中使用 JDBC PreparedStatement 時,它將對該語句進行一次編譯,而後將其放到緩存中以便再次使用,不只可以在建立 PreparedStatement 的同一方法中重用,還可以跨程序重用,只要當中使用了一樣的 SQL 代碼或者還有一個 PreparedStatement。省去又一次編譯的步驟可以極大減小調用 JDBC 驅動程序的次數,並且提升應用程序的性能。
要利用這個特性,您僅僅需編寫對應的 JDBC 代碼以使用 PreparedStatements,而不需要進行不論什麼其它工做。
在編寫代碼時。使用 PreparedStatement 取代常規的 JDBC Statement 類(它使用了純的動態 SQL),您就可以實現性能的加強,而不會損失不論什麼可移植性。
13. 充分利用現有的環境。
提供一個 Java EE EAR 和可配置的安裝腳本。而不是黑盒二進制安裝程序。
在大多數的實際場景中,大量的 WebSphere Application Server 用戶在一樣的共享單元中運行多個應用程序。
這意味着。若是您提供一個需要安裝的應用程序,那麼它必須能夠合理地安裝到現有的基礎設施中。這意味兩個方面:首先。您必須限制關於環境的若是的數目,並且因爲您沒法預料到所有的狀況。因此您的安裝過程必須是可見的。
這裏所說的可見是指。不該該提供二進制可運行文件形式的安裝程序。
運行安裝任務的管理員需要清楚安裝過程對他們的單元所進行的操做。爲了實現這樣的方式,您應該提供一個 EAR 文件(或者一組 EAR 文件)以及相關的文檔和安裝腳本。
這些腳本應該具備可讀性。以便安裝程序能夠知道它們需要運行的操做,並對腳本的內容進行驗證以確保不會運行不論什麼危急的操做。
在有些狀況下。腳本並不合適,用戶可能需要使用一些曾用過的其它方法來安裝 EAR。這表示您必須記錄安裝程序所完畢的工做!
14. 充分利用應用server環境所提供的服務質量。
設計可以使用 WebSphere Application Server Network Deployment 集羣的應用程序。
咱們已經介紹了利用 WebSphere Application Server 安全和事務支持的重要性。另外一個更重要的、常常被咱們忽視的問題。即集羣。需要將應用程序設計爲能夠執行於集羣的環境。大多數實際的環境需要經過集羣來實現可擴展性和可靠性。沒法進行集羣的應用程序很是快會致使災難的出現。
與集羣緊密相關的是支持 WebSphere Application Server Network Deployment。假設您正在構建一個應用程序並打算將它賣給其它人,請確保您的應用程序可以執行於 WebSphere Application Server Network Deployment,而不不過單個server版本號。
15. 利用 Java EE,不要欺騙。
致力於構建真正利用 Java EE 功能的 Java EE 應用程序。
有件很煩人的事情咱們曾屢次遇到過,某個應用程序聲稱可以執行於 WebSphere 中,但它並不是一個真正的 WebSphere 應用程序。咱們曾見過幾個這種演示樣例,當中有一小段代碼(多是一個 Servlet)位於 WebSphere Application Server 中。而其他所有的應用程序邏輯實際上位於單獨的進程中。好比一個以 Java、C、C++ 或其它語言(沒有使用 Java EE)編寫的守護進程負責完畢實際的工做。這並不是一個真正的 WebSphere Application Server 應用程序。對於這種應用程序。WebSphere Application Server 所提供的差點兒所有的服務質量都不可用。對於那些以爲這是 WebSphere Application Server 應用程序的人來講,他們會忽然的醒悟過來。原來並非如此。
16. 安排進行版本號更新。
更改是在所不免的。安排新的發行版和修復程序更新,以便您的客戶能夠得到最新的版本號。
WebSphere Application Server 在不斷地發展,因此 IBM 按期地給出 WebSphere Application Server 的修復程序,這是很是正常的,並且 IBM 還按期地公佈新的主要版本號。您需要爲此作好安排。這會影響到兩類開發組織:內部開發者和第三方應用程序供應商。主要的問題是一樣的,但對二者的影響則有所不一樣。
首先考慮修復程序。IBM 按期公佈建議更新,以修復產品中已發現的錯誤。
雖然不太可能始終執行於最新的級別,但請注意。不要隔得過久。那麼到底「隔多久」是可以接受的呢?對於這個問題沒有什麼正確的答案,但是您應該安排好對幾個月內的發行版進行修復級別更新。是的。這表示一年要更新好幾回。內部開發者可以忽略某些修復級別,一次僅支持一個修復級別,以減小測試成本。應用程序供應商則沒有這麼幸運。假設您是應用程序供應商。那麼您同一時候需要支持多種修復級別。以便您的客戶可以將您的軟件與其它軟件一同執行。假設您僅支持一種修復級別,那麼很是可能沒法找到同一時候兼容於多種產品的修復級別。實際上對於供應商而言,最好的方法是使用支持「向上兼容修復程序」的模型。
IBM 使用了這樣的方法來支持所集成的來自其它供應商的產品(如 Oracle®、Solaris™ 等等)。
有關更具體的信息,請參考咱們的支持策略。
如下再考慮一下主要版本號更新。IBM 按期地公佈新的主要發行版,當中對咱們的產品進行了基本的功能更新。咱們臨時繼續支持舊的主要發行版,但不會過久。這意味着您必須安排從一個主要發行版轉到還有一個主要發行版。這是不可避免的,並且應該在您的成本模型中加以考慮。假設您是供應商。這意味着您必須經常地對您的產品進行更新。以支持新的 WebSphere Application Server 版本號。不然您的客戶將停滯於不受支持的 IBM 產品,咱們曾屢次碰到過這樣的狀況。假設您正從供應商處購買產品。咱們鼓舞您要留心您的供應商。以確保他們承諾支持 IBM 產品新的版本號。
停滯於不受支持的軟件是一種很危急的狀況。
17. 在代碼中所有關鍵的地方,使用標準的日誌框架記錄程序的狀態。
這包含異常處理程序。使用像 JDK 1.4 Logging 或 Log4J 這種日誌框架。
有些時候,日誌記錄是最乏味的工做。下降了編程的價值,但是這樣作可以下降調試的時間。並儘快地完畢對應的任務。依據通常的經驗。在每個過渡的地方,需要進行日誌記錄。當您將參數從一個方法傳遞到還有一個方法,或從一個類傳遞到還有一個類。需要進行日誌記錄。
在對一個對象進行某種轉換時。需要進行日誌記錄。在碰到不解之處時。需要進行日誌記錄。
在決定了進行日誌記錄以後,需要選擇一種合適的框架。
實際上有不少選擇。但是咱們偏心 JDK 1.4 Trace API。因爲它們已全面地集成到了 WebSphere Application Server 跟蹤子系統中,並且是基於標準的。
18. 在完畢對應的任務後。請始終進行清理。
假設您從池中獲取了一個對象,請始終確保將其返回到池中。
無論執行於開發、測試或生產環境中,咱們發現 Java EE 應用程序最多見的錯誤之中的一個是內存泄漏。
絕大部分狀況是因爲開發者忘了關閉鏈接(大多數狀況下是 JDBC 鏈接)或將對象返回到池中。對於不論什麼需要顯式關閉的或需要返回到池中的對象,請確保進行了這種操做。
不要編寫出這樣糟糕的代碼。
19. 在開發和測試過程當中遵循嚴格的程序。
這包含採用和遵循軟件開發方法學。
大型系統的開發是很是困難的。因此應該十分慎重。
但是,咱們常常發現一些團隊疏於管理、或者不能全心全意地遵循相關的開發方法(這些方法可能不適用於他們正在進行的開發類型)、或者他們並無很是好地理解這一點。
最爲糟糕的多是嘗試每個月更換不一樣的開發方法。在單個項目的生命週期中,一個團隊從 RUP 改變爲 XP。以及一些其它敏捷方法。
總之,對於大多數團隊而言。僅僅要團隊成員能夠很是好地理解、嚴格地運行、並依據特定的技術本質和使用該方法的團隊進行適當的調整。那麼差點兒不論什麼一種方法都是有效的。對於那些還沒有採用不論什麼方法、或者那些不能夠全然地利用所選方法的團隊,咱們建議他們參考一些優秀的著做。如 [Jacobson]、[Beck1] 或 [Cockburn]。
還有一個有價值的信息來源是近期發佈的用於 Eclipse Process Framework [Eclipse] 的 OpenUP 插件。對於這個已經介紹過的主題,咱們不想作過多的反覆。建議讀者參考 [Hambrick] 和 [Beaton2](請參見參考資料)。
結束語
在這個簡短的摘要中。咱們已經向您介紹了 Java EE 中的核心模式和最佳實踐。它們使得 Java EE 開發成爲一種可管理的過程。雖然咱們並無給出所有在實踐中使用這些模式的必要細節,但是咱們但願能夠給您足夠的指點和指導。以幫助您決定下一步要作什麼。
致謝
感謝所有最初提出這些模式和最佳實踐的人(以及如下提到的人),此外還要感謝 John Martinek、Paul Ilechko、Bill Hines、Dave Artus 和 Roland Barcia 對本文的批閱。
參考資料
- [Alur] Deepak Alur、John Crupi 和 Danny Malks 合著的 Core J2EE Patterns(第二版),Addison-Wesley,2003 年
- [Bakalova] R. Bakalova 等撰寫的 WebSphere Dynamic Cache:Improving WebSphere Performance。IBM Systems Journal。2004 年第 2 期第 43 卷
- [Barcia] Roland Barcia 等撰寫的 IBM WebSphere:Enterprise Deployment and Advanced Configuration。IBM Press。2004 年
- [Beck1] Kent Beck 撰寫的 Extreme Programming Explained:Embrace Change。Addison-Wesley,1999 年
- [Beck2] Kent Beck 撰寫的 Test Driven Development by Example,Addison-Wesley,2002 年
- [Beaton] Wayne Beaton 撰寫的 移植到 IBM WebSphere Application Server,第 I 部分: 設計利於移植的軟件,IBM developerWorks
- [Beaton2] Wayne Beaton 撰寫的 理想的 WebSphere 開發環境,IBM developerWorks
- [Brown] Kyle Brown 等撰寫的 Enterprise Java Programming with IBM WebSphere,第二版,Addison-Wesley。2003 年
- [Brown 2] Kyle Brown 和 Keys Botzum 撰寫的 Improving HttpSession Performance with Smart Serialization,IBM developerWorks
- [Cockburn] Alistair Cockburn 和 Crystal Clear 撰寫的 A Human-Powered Methodology for Small Teams。Addison-Wesley。2004 年
- [Cox] Stan Cox 和 Brian K. Martin 撰寫的 Exploiting Dynamic Caching in WAS 5.0, Part1,e-Pro Magazine(2003 年 7/8 月)
- [Eclipse] Eclipse Process Framework
- [Fowler] Martin Fowler 撰寫的 Patterns of Enterprise Application Architecture。Addison-Wesley,2002 年
- [Hambrick] Geoff Hambrick 等撰寫的 爲何非功能性需求很是重要?,IBM WebSphere 開發人員技術期刊,2006 年
- [Ilechko] Paul Ilechko 撰寫的 ilechko。IBM developerWorks,2006 年
- [Jacobson] Ivar Jacobson 等撰寫的 Unified Software Development Process。Addison-Wesley。1999 年
- [Jewell] Tyler Jewell 撰寫的 Stateful Session Beans:Beasts of Burden,OnJava.com
- [Joines] Stacy Joines、Ken Hygh 和 Ruth Willenborg 撰寫的 Performance Analysis for Java Websites。Addison-Wesley,2002 年
- [Marinescu] Floyd Marinescu 撰寫的 EJB Patterns。John Wiley & Sons,2002 年
- [Schwaber] Ken Schwaber 和 Michael Beedle 撰寫的 Agile Software Development with SCRUM,Prentice-Hall。2001 年
- [Wiki] Wiki Web, http://c2.com/cgi-bin/wiki?ModelFirst
- [Willenborg] R. Willenborg、K. Brown 和 G. Cuomo 撰寫的 Designing WebSphere Application Server for performance:An evolutionary approach,IBM Systems Journal,2004 年第 2 期第 43 卷