java開發正處于一個十字路口。開放的標準已經為Java平臺和語言帶來了很多益處,但它們也帶來了一些問題。開發人員經常對Java開發的復雜性感到頭疼。更糟糕的是,復雜度是如此嚴重,以至于實際的業務問題反而處于次要地位。
J2EE規范提供了許多API、標準和開放的終端,允許架構師、設計師和開發人員建立出眾的企業系統。在權衡選擇適當技術時必須小心。
技術的發展為開發人員帶來的更多是困惑(除非開發人員是無所不能的),而不是幫助他們解決這些問題。通常情況下,架構師和開發人員將大多數時間花在對選中框架的支持上,而不是用來解決手頭的業務問題。
本文將討論在使用EnterPRise Java Beans (EJB)規范設計和開發出眾的J2EE應用程序的過程中所涉及到的技術。盡管本文的目的不是展示如何使用EJB,但是我還是會談到EJB開發過程中的各種陷阱,主要集中于現實世界中的一些反模式,這些反模式已經偷偷進入您的開發過程中。
按部就班地學習固然不錯,但是由于日益縮短的開發周期,從其他人的錯誤中學習是更明智的方法。對常出現危險的位置的全面了解將有助于采用主動的策略,而這正是本文的主題。我們將從J2EE應用程序的EJB上下文開始,并討論存在于EJB開發中的一些潛在危險。
軟件是一種設計藝術,并且設計是不斷延伸的。隨著每種激動人心的技術(如:EJB規范)的出現,疲倦的工程師往往都急切地采用新技術。這是大多數EJB項目會失敗的原因之一。通常它們一敗涂地,以至于得不到任何回報。這樣更明智一些:慎重對待EJB的抉擇,而不是僅僅因為它是一種很熱門、很有吸引力、有前途的技術就采用它。
論及用于構建分布式的事務型長期業務解決方案的組件架構,要決定是否要在軟件項目中使用EJB,需要用良好的設計實踐進行認真的分析和主動的規劃。
“當您手中有一把錘子時,任何東西看上去都像釘子。”這個諺語適用于大多數EJB選擇。對于大多數項目來說,EJB可能不是最佳選擇,因為存在如下情況:
圖1 展示了在項目規模和成本方面,簡單的POJO(Plain Old Java Objects)解決方案與EJB解決方案之間的折衷。
在初學者和中等水平的用戶中間最常見的對EJB的誤解是,如果使用EJB的話,每個組件都是一個EJB。
錯了,這種判斷很少是成立的。某個組件或子系統可能真的是候選的EJB,但是其他組件或子系統可能只是POJO。這種混合模式的設計將很難進行,但是慎重對待每個組件/子系統級的設計決策可以讓轉出時的工作變得比較容易。
在子系統級選擇EJB的一個重要問題是理解EJB服務。EJB組件呈現兩種風格:一組作坊組件,稱為會話bean;以及一組持久性組件,稱為實體bean。會話bean通常是粗粒度服務,利用容器的功能提供分發、事務管理和安全性。對于非EJB組件,實現這些服務是開發人員的責任。那些大量使用了這些服務的組件通常是會話EJB的正確候選者。
EJB規范通過實體bean實施對細粒度持久性服務的支持。每個實體bean本身也都可以是分布式的、支持事務的、安全的,因此存在細粒度和粗粒度服務的復雜混合。這種混合往往使實體bean組件很難管理。如果只需要一個組件是持久的,那么很少需要將該組件作為EJB。存在其他更易于維護的、流行的輕量級持久性框架(例如:JDO、Hibernate等)。
EJB設計的一個關鍵問題是創建接口。接口是EJB組件的通用語。它們是將EJB組件所提供的服務暴露給外部世界的手段。拙劣的接口設計將會導致EJB很難維護和修改。
您的網絡管道有多大? 到目前為止,EJB采用的還是RMI。它涉及到遠程過程調用。位置的透明性只會提高網絡的復雜性。EJB調用涉及到通過網絡編組和解組參數(非常重要?。T谠O計這些遠程接口時必須十分小心。如果有一個可以允許大量數據迅速流過的大管道,那么接口可以是粗粒度的。反之,如果擁有的帶寬較窄,那么細粒度的接口結合輕量級的參數編組會更好一些。
是否需要外觀(façade)?事先應該考慮好是否要使用外觀作為其他EJB組件的網關,事后再思考就沒有什么意義了。一旦決定使用外觀,就可以設計外觀來返回作為值的集合的對象。細粒度訪問將由外觀來處理,并且由于它通常在容器內,所以將會十分有效。這樣就可以減少到遠程服務器的往返次數。
使用外觀。但是如何使用外觀才好?在設計EJB接口時,對于設計遠程接口而言,關鍵是要盡量避免狀態,而且遠程接口使用粗粒度即可。粗粒度接口設計不一定意味著在一個外觀中集中EJB層中的所有方法。通常情況下,將多個外觀用作EJB組件的網關是比較好的方法。在設計基于EJB的架構時,最安全的方法是在面向對象的域模型與過程遠程服務層之間找到一個平衡點。
異常處理是EJB開發中另一個最讓人困惑的領域。從本質上來說,異常是對預期行為的偏離。這些中斷在分布式架構中非常常見,因為涉及到太多異構環境,而這些環境全都通過網絡連接。一個網絡故障就能引發一場災難。EJB中的異常處理特別復雜,而且涉及兩種類型的異常。下面是處理異常的一些指導原則。
在開發MDB時,應該特別注意識別可能引起“熱土豆”問題的代碼區域。其解決方案是將確認和消息處理分為兩條執行路徑。一接收到消息就立即確認。當在消息處理過程中出現異常時,可能需要將異常寫入錯誤隊列。
EJB規范通過一個稱為實體bean的特殊bean類來處理持久性服務。實體bean的目標是將域數據模型抽象化。就這一點而言,如果底層的數據源是關系型數據庫管理系統,那么實體bean代表的就是數據庫表中的行。最初的規范激起了許多關于實體bean及其用法的爭論。此后,持久性API在1.1和2.0規范中重寫了兩次。
由于持久性是一種細粒度服務,它必然不適合EJB服務的粗粒度特性。這帶來了一些困惑:如何使用實體bean才最好?在做出使用實體bean的決定之前,建議先對其他持久性模型進行認真的評估。如果決定使用實體bean,那么應該仔細考慮和評估下面的問題。
由于實體bean的細粒度特性,當直接把它們暴露給客戶端時,很容易產生反模式。一個最常遇到的問題可能是n + 1問題。它是指為了檢索一個業務實體的n個屬性,需要n+1次遠程調用。額外的一次調用是從EJB容器獲得遠程存根。通過無格式的POJO DAO實現同樣的檢索功能會更簡單一些。只需用一個JDBC調用來檢索行。
一個與暴露實體bean相關的更微妙的問題是事務完整性的缺失。考慮一個具有三個mutator方法的實體bean。進一步假定客戶端需要更新事務中兩個mutator方法所代表的實體的兩列??蛻舳巳绾伪WC實體bean上兩個連續的更新方法之間的事務完整性?唯一的方法是使用會話外觀來包裝實體bean。
在應用程序代碼中管理實體關系將會引起嚴重的性能問題。Java沒有針對數據庫查找進行過優化。在Java代碼內部模擬應用程序連接是一個壞的編程習慣。數據庫使用成熟的技術來優化查詢訪問計劃,從而將數據比較的次數降至最少。例如,在應用程序中,給定一個地址實體查找Person實體的動作無法調節。這些類型的關系能夠按照CMR字段(源于EJB 2.0)得到最好的表示。應用程序在循環結構中為模擬關系連接而進行的比較的次數將會對應用程序的性能產生重要影響。
用長的主鍵設計實體bean將會導致性能隨著數據存儲區中數據的增長而下降。主鍵被數據庫用于查找。數據庫索引大量利用主鍵來建立哈希表。與短主鍵相比,長主鍵在建立哈希表的過程中需要更多的計算。數據庫緩存索引字段來優化關系連接的性能。長主鍵往往會在緩存中占用許多空間,從而促生系統失效情況。
然而,多長才算長呢?對于主鍵可以有多長,不存在基準。長度依賴于目標數據庫表中的數據量。
不管在開發過程中是否采用了良好的設計、編碼和工程方面的實踐,系統都需要進行調優,對于基于EJB的系統來說這尤其正確,因為它們非常復雜,難以進行高級測試。下面是一些性能調優的指導原則。
以靈活性和可伸縮性的名義用XML來填充JMS消息不能解決一切問題。由于XML是新的熱門技術,大多數設計師/開發人員往往過度使用XML。當存在其他的靈活選擇時,XML的過度使用會嚴重影響應用程序的可伸縮性。
XML是一項偉大的技術,它將不同種類的環境集中在一起,但最好能理智地使用它。記住,XML也增加了開銷。因為XML是無類型的(所有的內容都是字符串),所以必須進行類型轉換和檢查。此外,分析龐大的XML消息是一個非常耗費資源的過程。XML的過度使用通常出現在JMS實現中。在這種情況下,MDB會花費許多時間進行類型檢查并分析收到的XML消息。
EJB規范的目標之一是允許創建可移植組件。然而在現實中,它必須依賴于容器提供者所提供的擴展和增強。例如,每個供應商都有其私有的部署描述符,該描述符允許調優EJB實例的行為。重要的是要認識到,可移植性是一個希望有的功能而不是必需的。企業很少改變應用服務器,很可能要在同一個服務器上部署EJB。因此充分利用容器提供者所提供的額外功能是很明智的做法。
正如前面所討論的,實體bean本質上不適合分布式服務的粗粒度特性。此外,它們非常耗費資源,而且難以更改和維護。使用實體bean的最初目標是能夠在機器A上部署一個域模型,在機器B上部署另一個域模型,使它們能夠通過位置透明性進行無縫地互操作。由于通過網絡連接,這很少是正確的。這導致開發人員調整實體bean模型,而這只能讓事情變得更糟。
隨著輕量級容器的逐漸流行,我們有了非常好的提供透明持久性的替代方案。例如,來自于開源領域的Hibernate。它向POJO提供了透明持久性服務。它易于配置,不需要完全的J2EE容器。Sun制定了一個通過JDO實現透明持久性的新標準。盡管JDO還處在初期階段,并且還沒有完全被J2EE供應商所接受,但它提供了許多希望,而且它是一個相當簡單的API。
分布式組件是長期投資,它們在公司的IT基礎架構中起著很重要的作用。它們被大量使用,一個故障就會引起巨大的損失。必須小心確保中間件組件在生產中運行良好。這可以通過開發生命周期中每一個階段的嚴格測試來保證。EJB組件需要專門的測試,因為它們存在于一個托管環境(容器)中。從設計到編碼到集成和部署,EJB組件應該使用完全真實的用例進行測試,以便確保更平滑的生產過渡。
在實現通過簡化開發來提高開發人員的生產力的承諾方面,EJB架構可能是僅有的敗得如此慘重的J2EE組件。EJB 3.0正在通過降低EJB的復雜性再次試圖實現這一承諾。
EJB 3.0減少了開發人員需要提供的編程工件的數量,消除了需要實現的回調方法或將其減至最少,降低了實體bean編程模型和O/R映射模型的復雜性。下面是EJB 3.0規范的主要新特性。
早期編程模型的問題之一是EJB需要許多類和描述符。從EJB 3.0開始,不再需要接口或部署描述符。只需一個得到充分注釋的EJB類(本質上是一個POJO),為容器提供運行時信息。
從決定使用EJB到生產部署,每一步都需要認真地考慮、分析和規定。本文為EJB開發提供了一些指導原則,并展示了EJB開發中的一些潛在的灰色領域。然而,新的反模式不斷出現,這要由架構師、工程師和開發人員來解決。
EJB 3.0確實是向簡化EJB開發邁出的一大步,這不僅表現在其編碼部分。能夠編寫簡單的EJB將使維護更加方便,并降低生產中的風險。J2EE和擴展的EJB現在是企業應用程序的默認開發平臺。
要有效使用EJB,需要理解EJB只是J2EE的一個擴展。J2EE應用程序不一定要使用EJB。但是,在需要時,EJB能夠為應用程序提供重要的優勢。開發有效EJB的關鍵是,避開那些說得天花亂墜的虛假宣傳,根據EJB本身的能力來評估該技術。這將幫助您做出更好的決策,理智地使用EJB,最終構建有效的EJB。
希望本文能對您有所幫助!
原文出處: Effective EJB: Make EJBs Work For You http://wldj.sys-con.com/read/138258.htm
(出處:http://www.49028c.com)
新聞熱點
疑難解答