Enterprise JavaBeans (EJBs) 到底有什麼了不起的,為什麼對 Java™ 2 Platform, Enterprise Edition (J2EE) 開發來說如此重要?在這一期的 Geronimo 叛逆者 專欄中,OpenEJB 的共同創始人 David Blevins 將介紹 EJB 可以為您做什麼,並解釋 OpenEJB 如何被選擇作為 Apache Geronimo 的 EJB 實現。
簡介
說實在的,在我 看來,EJB 並不好用。它們需要開發人員在應用程序中投入比他們想像的還要多的精力;它 們引以為基礎的接口強制您實現許多您甚至根本不需要的功能;而且因為您需要在容器中運 行它們,所以使用 JUnit 將它們與應用程序的其他部分一起測試是十分棘手的。
但 是,它們也許恰恰正是 J2EE 開發的基石。
所以當 The Powers That Be 邀請我在這 一期 Geronimo renegade 中選擇 OpenEJB 作為 Apache Geronimo 的 EJB 實現時,我的興 趣被激發了。也許我能最終弄清楚它到底有什麼了不起的。
OpenEJB 如何成為 Apache Geronimo 的一部分
我曾打電話給 David Blevins,他與 Richard Monson- Haefel 在六年前共同創建了 OpenEJB,他還創建了 Geronimo。我想知道 OpenEJB 為 Geronimo 提供了什麼,以及 EJB 本身為開發人員提供了什麼。
我首先問他 OpenEJB 是如何在 Geronimo 等比較大的項目中興起的。David 解釋說,他在 Geronimo 尚未正式發 布、只是一個傳聞的時候就已經支持 Geronimo 項目了。“所以我絕對是所謂的 Geronimo 陰謀的一部分” ,他開玩笑地說。
哈,又是陰謀。我問他為什麼總 是這樣形容 Geronimo 呢。“哦,Geronimo 真的非常 FUD(恐懼,不確定,懷疑), 對於如此標榜我們的那些人來說。” 他解釋說,Geronimo 創始人的目標首先是將將合 適的人聚集起來,然後才考慮合適的組件。“參與創建 Geronimo 的個人基本上都將自 我和自己的代碼拋在一邊,而決定首先將自己投入項目中” ,David 告訴我。基本上 ,他們是從一張白板開始嘗試創建項目的。
那麼 OpenEJB 是如何成為這張白板的一部分呢?“哦,我猜原因就是您所知道的那 些”,David 說。但他並不十分嚴肅。事實上,一開始是最初的 Geronimo 創始人之一 的 Dain Sundstrom 邀請他加入該項目的。Dain 實際上在一年前就曾試圖聘請 David 參與 一個類似的開放源碼項目:“有一段時間,他參加了 Twin Cities Java Users Group (TCJUG) 的每一次社交聚會,並不斷就此事糾纏我。”
當他們確實走到一起時 ,真的是命中注定一樣。雖然他們兩個都來自 Minnesota,但組建 Geronimo 項目的時候, David 正在 San Francisco 任教。“我說,‘這樣吧,我現在在 San Francisco ,所以您必須等到我返回 Minnesota。’ 當然他說,‘太好了,我也在 San Francisco’ ,他剛從一個會議返回來。所以那天我們正好在 San Francisco 聚到一 起討論,他本來以為會繼續得到我一直給他的 no。但當重心從另一個項目轉到 Apache J2EE 實現時,答案立即變成 yes。”。
而且,作為 OpenEJB 的領導人(因為 Monson-Haefel 在幾年前已經離開),David 決心圍繞 Geronimo 的工作重振該社區。 “我們只知道這是應該做的事情”,他說。
不僅如此,OpenEJB 和 Geronimo 這兩個團體建立了大型項目中罕見的協作。OpenEJB 的 Alan Cabrera 編寫了 Geronimo 的安全系統。Aaron Mulder,一本有關 Geronimo 的可自由下載的書籍的作者,也 鄭重其事地檢查了這個由 IBM® 捐獻的控制台。Geronimo 的 Dain Sundstrom 和 David Jencks 為 OpenEJB 做了不計其數的工作,以使其遵循 EJB 2.1(Open EJB 原來只遵循 EJB 1.1)。Gianny D'Amour,Geronimo 的早期附加物,全力促進 David 稱為 “我所 見過的最大的 Geronimo 或 OpenEJB 補丁,基本上完成了我們的 CMP(container-managed persistence,容器管理持久性)實現” 。Jacek Laskowski,一位 OpenEJB 的長期貢 獻者,第一個開始了 Geronimo-Tomcat 集成工作,該工作由 Geronimo 的 Jeff Genender 驅動完成,Jeff Genender 最終也成為 OpenEJB 的貢獻者。
Apache 孵化器
事實上,當談到 OpenEJB 和 Geronimo 時,David 說,“它在很大程度上是一個社區” 。這就是為什麼當 Geronimo 邀請 OpenEJB 成為 Apache 的一部分時答案又一次是 yes 的 原因之一。
OpenEJB 仍在獲取所有必要的文件,以成為 Apache 孵化期的一部分,任何第三方,比如 持有任何一部分代碼版權的公司,需要以書面形式作出正式的授權和捐獻。之後,OpenEJB 代碼在孵化期的子版本中就有了自己的區段。郵件列表將位於孵化期領域之下,諸如此類的 事項更方便了兩個項目涉及的工作。
孵化期曾被描述為密封過渡倉 (airlock) 一類的東西。因為項目曾被邀請成為 Apache 的一部分但還沒有正式被接受。為了保證從孵化期畢業,項目必須適應所謂的 Apache 做事 方式。“有許多標准”,David 解釋說,“但基本上您必須展示一個健康的社區,您必須有 干淨的 IP”。
項目目前正致力於這個過程中所謂的干淨 IP 方面,並正在獲取來自曾資助早期開發的公 司(比如 Intalio)的退出。但一個健康的社區不成問題。項目已經存在六年了,有許多熱 忱的貢獻者。(這個隊伍階層已經隨著 Geronimo 的加入而顯著膨脹。)這種多樣性對 Apache 來說至關緊要。David 解釋說,“多樣性是代碼和社區在人力資源撤退時存活下去的 關鍵因素。” 換句話說,當社區的一部分人離開一段時間時(這在任何長期項目中都是必不 可避免的),社區作為一個整體必須足夠強壯和多樣化才能生存。
同時,OpenEJB 必須至少使一個發行版成為孵化期過程的一部分。項目已經因為參與 Geronimo 受到了極大的影響,尤其是在容器方面,需要投入大部分工作升級到 EJB 2.1。
OpenEJB 的兩端
OpenEJB 實際上包括兩個部分 —— 服務器和容器,團隊強調將二者分離。EJB 規范將容 器和服務器合同描述為不同的兩部分,但從沒有實際定義這些部分。OpenEJB 定義了容器-服 務器合同,最終 OpenEJB 的服務器部分幾乎原封不動地合並到 Geronimo 中,但容器部分在 該項目中被完全重寫。“我們沒有全部使用 Jetty,而且沒有全部使用 OpenEJB,OpenEJB 在 Geronimo 存在之前已經到處都是了”,David 說。“讓我們(Geronimo 社區成員)引以 為豪的一件事是我們只是隨機地聚集起來一群人,並成就了弗蘭肯斯泰因般的結果。”
OpenEJB 的服務器端處理等式的分布式部分。在任何分布式系統中都需要兩樣東西:定位 要使用的組件或服務器的能力,以及定位之後調用組件或服務的方式。定位組件或服務通常 需要類似注冊的操作。在 Web 服務中為 “統一描述、發現和集成” (Universal Description, Discovery and Integration, UDDI)。在 CORBA 中為 CosNaming。在 EJB 中為 “Java 命名和目錄接口” (Naming and Directory Interface, JNDI)。理想情況下, 您應該能夠通過正常編程方式實現第二部分 —— 調用組件。換句話說,您應該能夠像調用 本地對象一樣調用組件。
環境的服務器部分處理該調用過程,該部分確保調用到達實際遠程對象,並確保響應返回 給客戶機。服務器還處理任務,比如 “通過調用通信事務處理安全狀態” ,David 說。
我必須承認,對於 Plain Old Java Objects (POJO) 來說這是相當棘手的事情。我已經 開始看到使用 EJB 的優點。但我仍然是一個 Web 服務小子,所以遠程系統嚇不倒我。EJB 還能為我這個程序員做什麼呢?基本上,它似乎主要以由容器執行的函數為中心。
EJB 能為您做什麼
有三種類型的 EJB —— 會話 bean(無狀態的和有狀態的)、消息驅動 bean (MDB) 和 實體 bean。“我從來都不喜歡術語無狀態 或有狀態”,David 承認,“因為它們都保留狀 態。只是它們對狀態具有不同的保證。我曾經教過 EJB(課程),我總是告訴我的學生將它 們看作專用實例和共享實例。專用實例是有狀態的會話 bean,共享實例是無狀態會話 bean 。可以將共享組件看作從圖書館借來的書。如果在讀完之後歸還它,則可以再次簽出,但不 能獲得物理相同的同一本書,即使其標題相同。有的人可能在裡面塗寫了,您在訪問這本書 時必須將這些考慮在內。”
專用或無狀態的 bean 沒有這個問題,因為一旦您請求一個這樣的 bean,它就是您的了 。其他任何人都不能使用該組件實例,所以可以確保任何塗改都是您的。這裡的挑戰在於, 您現在冒著累積服務器上幾乎無數個這種私有狀態的風險,所以需要一種方法來將那些目前 不使用的狀態推到磁盤中。所有這些都由容器處理。
容器還管理 MDB,從而使您可以很容易地使用 Java Message Service (JMS) 來回傳遞消 息。您可以通過 JMS 以事務處理方式調用(消息驅動),這是一個非常方便的特性”, David 解釋說。“您不必編寫許多代碼。您必須做的就是實現接口,而請求是從 JMS 到達您 那裡的。”在這種應用程序中,不必太多關注接收您消息的客戶機的形式。
還有實體 bean 的問題,它具有自己的優點 —— 主要是持久性和高速緩存方面。例如, 您可以從數據庫提取信息,並使用實體 bean 在事務處理期間高速緩存數據。“老實說,如 果讓您親自編程,您會發現這種優化是非常困難的”, David 說。
OpenEJB 容器
該功能全部都由容器負責。容器 “管理無狀態 bean 池以及無狀態 bean 和實體 bean 的高速緩存區”,David 告訴我,“當調用來臨時,它會進行必要的工作,將組件准備好以 便調用。它在調用前准備好所有事務狀態或確保所有安全要求,然後一旦發生調用,它將處 理任何類型的故障,比如回滾事務處理等,然後將請求發送給要與客戶機通信的服務器。”
好了,容器要做的事情實在太多了。就容器而言,使用 bean 可能要比試圖親自管理一切 要值得。但這並不是容器所做的全部事情。容器還可以管理每個組件的生命周期。
您可能說,“那這意味著什麼呢?” 這意味著容器明確知道要發生在組件上的事情並能 夠讓您知道。例如,您可能想知道它何時將調用一個組件,是當它在組件中啟動一個事務之 前、在結束一個事務之前,還是在銷毀一個組件之前,等等。您為什麼想知道?因為您可以 在那時實際執行操作。例如,您可以實現回調,即在事務處理完成時或回調時發送消息。這 使您可以完全控制組件的生命周期。
能力的代價
但這種能力不會沒有代價。這個代價就是您必須實際實現所有這些回調,不管您是否使用 它們。這對不需要 EJB 提供的全部功能的程序員來說是一個問題,因為實現每個回調的問題 不在於 EJB 實現的選擇,而在於通過無格式舊 Java 接口實現 EJB 這一事實的後果。“如 果您有較低端的需求,那麼使用這個 API 開發是相當麻煩的” ,David 說。
幸運的是,大多數復雜性將隨著 EJB 3.0 的到來而消失,這是 EJB 構造方式的主要變化 。不需要實現這些接口和回調,只需要注釋無格式的舊 Java 類即可。“在 EJB 3.0 中,只 能說 ‘乒,那是一個組件,我已經將之標示為無狀態” ,David 解釋說。要實現回調,只 需創建方法並適當地將其注釋即可。“為了減少你這邊的工作,它需要實現很多,因此出現 了這些反模式(人們為使用會話定位器的 EJB 找到的),還有類似的所有這類瘋狂的東西, 他們能夠基本屏蔽了 EJB API,但是還可以用-- 所有這些東西現在還不是必需的。”
當然,這些留待將來解決,等到 OpenEJB 3 分支開始成為 Geronimo 一部分的時候(我 猜想)。但即使現在也存在 OpenEJB 與應用服務器如此配合的必然原因。
挑選
您可能知道,Geronimo 基於 GBeans 的概念,它允許您作為管理員來確定到底想要 激活哪個組件。所以您可以具有超流水線的版本或超工業強度的版本,但您應該選擇您希望 支持的版本。OpenEJB 十分符合這個概念,因為服務器和容器之間的徹底分離使得用戶可以 非常靈活地確定要支持的工具。例如,盡管一些 EJB 系統要求您具有服務器要提供的 CORBA 、Web 服務和任何其他工具,OpenEJB 允許您通過將每個工具包裝為 GBean 來挑選。這樣, 您就可以具有兩個不同的 CORBA orb、任意數目的 Web 服務實現和其他任何您認為必要的工 具。或者,您還可以一個也不支持且僅允許本地調用。此外,通過服務器的構造方式,您可 以支持多個工具而不必具有應用服務器甚至應用程序的多個副本。(作者注:David 指出, 這種能力對於 Web 服務尤其有用,其目的在於完全的互操作性,但現實有時無法達到這種目 標。)
前方的路
向前看,OpenEJB 有一些令人興奮的特性即將面市;一些是 嶄新的,一些不太新。例如,David 對容器驅動測試的嵌入式可測試性的擬定回報感到非常 興奮。這種能力使得用戶可以容易地使用 JUnit 測試 OpenEJB 組件。通常,這些組件沒有 容器不能運行,並要求您在測試前和拆卸後執行特殊設置。但嵌入式可測試性允許您創建一 個環境,將容器包含在其中作為系統的嵌入式部分,同樣地,您可以嵌入類似 IBM Cloudscape™ 的數據庫。“這是 OpenEJB 1 中包含的東西,在 OpenEJB 2 中丟 失了,我們將在 OpenEJB 3 中恢復”, David 解釋說。“所以如果您編寫 OpenEJB 組件,那麼您可以毫不費力地用正常的 JUnit 測試運行它們。 ”
OpenEJB 3 還將著眼於支持 Java Persistence Architecture API (JPA)。 David 介紹說,“OpenEJB 在過去偏向於使用其他組件實現其持久性。在 OpenEJB 1 中,我們使用了 Castor,在 2 中使用了 TranQL。在 3 中我們將使用 OpenJPA,該 API 目 前是標准,所以 OpenEJB 3 將是可插拔的。所以如果 TranQL 或 Castor 或任何其他項目確 實決定支持 JPA,我們將能夠支持它們中的任何一個,或者同時全部支持。 ”
OpenEJB 還將支持構造器注入,從而使得容器可以在運行時提供各種類和對 象。EJB 3.0 規范談到了公共字段注入和 setter 注入,但構造器注入將使您可以避免為預 期不會更改的值創建 setter。當然,它還能夠幫助避免使用公共字段實現相同功能的必要性 。“我們在 1995 年基本停止了這種行為,大約在 Java 發明三天後”,David 聲明。
結束語
有了持久性、事務管理並認識到對該 API 的編程將不會始終如 此痛苦,我可以看到深入調查 EJB 的價值所在,尤其是對於注定要在 Apache Geronimo 上 運行的項目來說。它們在 Web 應用程序中是強大的力量,事實上,甚至在非 Web 應用程序 中也是如此。請參閱本文 參考資料 一節中的鏈接,以幫助您繼續自己的調查。