Bruce Tate , 總裁, J2Life, LLC
輕量級容器可以動態地使系統主要組件之間的耦合變松散。不同的容器包含相同的設計模式,但卻具有根本不同的哲學。本文幫助您在下列三種輕量級容器之間作出最佳選擇:Spring Framework、HiveMind 和 PicoContainer。
2002 年在科羅拉多的一次旅行中,我完美地感受了阿肯色河。在三段不同的漂流中,這條河展示了令人驚異的多樣性。柔美的布朗峽谷有著開闊的急流,翻滾著巨大的波浪。Royal Gorge 別具特色的懸崖峭壁引導著巨大而筆直的峽谷之下的水力,在這條直線上發生一點小閃失都會受到長途游泳的懲罰。Numbers 具有精密的落差,需要人們在范圍狹窄的圓石花園里精確操縱。在一條河里,我有了三次極不相同的體驗。
在我的上一篇文章“輕量級開發的成功秘訣,第 3 部分:Spring 露出水面”中,我們學習了輕量級容器的基本原理。本文將向您展示三種最流行的容器:
這三種容器都源于依賴注入,但每種容器都具有極不相同的特征。當我介紹每種容器的高級描述時,您將看到正在運行的每種框架,以及可以應用每種框架的環境。
核心哲學
這三種容器都接受 POJO (plain old Java object),都具有對象生命周期的鉤子(所以它們可以在創建或銷毀 bean 時調用您的代碼),都執行依賴注入。您可能認為這些主旋律將導致相似的容器,但事實并非如此。盡管植入每種容器的代碼可能相似,但容器本身反映了不同的能力、風格和整體哲學。總而言之,每種容器的作者都忠于他們的哲學。
Spring Framework
作為開放源碼框架的 Geneva,Spring Framework 為數百個 Java 2 Platform, Enterprise Edition (J2EE) API 和開放源碼框架提供了輕量級容器和膠水代碼 (glue code)。Spring 有一個最重要的前景:讓 J2EE 更易使用。讀完一些示例和書籍之后,您將看到一些常見的主題:
- Spring 支持三種依賴注入——setter、構造函數 和 方法 注入——但總的來說,最流行的模型是 setter 注入。
- 在靈活性和簡單性之間,Spring 的 XML 風格配置更重視靈活性。您可以做任何事情,但對于初學者來說,配置文件是晦澀難懂的。
- Spring 的創始人認為,容器只是整體框架的一小部分。Spring 的大部分價值來源于支持該框架的數千行膠水代碼。它易于插入任何系統中。
- Spring 框架是三種容器實現中最完美的。一般來說,優秀的文檔都是完美編寫的。
- Spring 具有自動連線 (autowire) 方式,但大多數示例都沒有使用它。我并不十分了解這個決策,但有時候,能夠看到明確列出的依賴關系是不錯的。
- Spring 提供了完整的 AOP 框架,使得更容易附加服務。您可以使用 Spring 自己的框架或依賴豐富的 AspectJ 集成(參閱 參考資料)。
如果要用一個短語來形容 Spring,我會說讓企業更強。
HiveMind
Howard Lewis Ship 是 Jakarta Tapestry Web 框架的創建者,他還創建了 HiveMind。作為一個容器,HiveMind 是靈巧、干凈且易于使用的。與其他許多較好的開放源碼框架一樣,Ship 創建 HiveMind 是為了讓它幫助解決現實問題。但是,HiveMind 向傳統的輕量級容器添加了兩個創新:
- 最重要的 HiveMind 創新是模塊。據 Ship 所說,Eclipse 插件激發了他的 HiveMind 模塊的靈感。
- HiveMind 強制您編寫接口。(與所有輕量級容器一樣,它不提供接口,而由您自己提供接口。)
- HiveMind 是用戶友好的,它提供稱為 HiveDoc 的文檔工具,友好簡明的 XML 配置,以及行準確的錯誤報告。
- HiveMind 用戶通常優先選擇 setter 注入,但該容器還支持構造函數注入。
如果用一個短語來形容 HiveMind 的話,我會說它是概念正確 的。
PicoContainer
到目前為止,PicoContainer 最重要的特征是它的尺寸。它沒有提供許多附加物,但它具有完整的依賴注入容器。PicoContainer 還具有一些惟一特性:
- PicoContainer 很小,所以它沒有攔截器、AOP 或相似類型的服務,而選擇了讓其他框架創建這些服務。
- PicoContainer 支持 Java 配置技術,而不支持 XML 配置技術,這與其他容器一樣。
- PicoContainer 流行的使用模型是構造函數注入,但它也支持 setter 注入。
- PicoContainer 沒有提供許多文檔,而且一些現有文檔是不完整的,但您不會太需要。
- PicoContainer 具有一個自動連線方式,它很不錯。
- PicoContainer 的發展似乎有點停滯。
如果用一個短語來形容 PicoContainer 的話,我會選擇理論完美,但不如 Spring 或 HiveMind 實用。
編程模型
現在我將向您展示社區中流行的編程示例,以幫助您更好地理解容器的作者希望您如何使用它們。我使用 PicoContainer 中的 Kiss 示例來展示 autowiring 和 Java 技術風格的配置,使用 HiveMind 加法器示例來展示模塊能力,使用 Spring PetClinic 應用程序來展示 Hibernate 集成。
Kiss 示例 (PicoContainer)
在這三個容器中,PicoContainer 具有最簡單的編程模型。要查看 Kiss 示例,可從 PicoContainer.org 下載它。安裝該示例,瀏覽到 docs\Two+minute+tutorial.htm,然后您會看到兩個組件:
清單 1. 兩個 Kiss 組件
public class Boy {
public void kiss(Object kisser) {
System.out.println("I was kissed by " + kisser);
}
}
public class Girl {
Boy boy;
public Girl(Boy boy) {
this.boy = boy;
}
public void kissSomeone() {
boy.kiss(this);
}
}
|
這兩個類是自解釋的。Girl 對 Boy 有依賴關系。該依賴關系將通過構造函數被注入。先實例化一個容器:
MutablePicoContainer pico = new DefaultPicoContainer();
|
然后注冊兩個組件:
pico.registerComponentImplementation(Boy.class);
pico.registerComponentImplementation(Girl.class);
|
稍后您可以向 PicoContainer 請求一個對象,然后操作它:
Girl girl = (Girl) pico.getComponentInstance(Girl.class);
girl.kissSomeone();
|
這樣就差不多了。編程模型是優雅的,基于構造函數的風格意味著您無需包括無參構造函數。對本例中的 Girl 調用這種函數將會使該對象處于不一致的狀態,因為 kiss
方法將拋出異常。
加法器示例 (HiveMind)
現在,讓我們看一下 HiveMind 的編程示例。從 Apache Jakarta Project 下載 HiveMind,然后查看加法器示例。您會看到接口和實現。(記住:HiveMind 強制編寫接口。)
清單 2. 加法器示例接口和實現
public interface Adder
{
public double add(double arg0, double arg1);
}
public class AdderImpl implements Adder
{
public double add(double arg0, double arg1)
{
return arg0 + arg1;
}
}
|
將該服務暴露在 XML 文件中,如下所示:
清單 3. 將該服務暴露在 XML 文件中
然后,其他應用程序就可以使用該服務了,如下所示:
清單 4. 其他應用程序可以使用該服務
Registry registry = RegistryBuilder.constructDefaultRegistry();
Adder adder = (Adder) registry.getService("examples.Adder",
Adder.class);
... adder.add(arg0, arg1)
|
注意,HiveMind 的模塊讓您可以將多個服務組合到一起。如果您需要向容器中的服務添加功能,可以使用攔截器:
清單 5. 使用攔截器添加功能
PetClinic 應用程序 (Spring)
Spring 處理事情的方法有些不同。因為 Spring 框架不帶有簡單的應用程序,我從我的書籍 Spring: A Developer's Notebook 中選擇了一個。您可以從 O'Reilly Media 獲取該示例代碼。解壓示例 4,它展示了一個用于 RentaBike 商店的帶有屬性的 CommandLineView
對象,該對象最終成為該應用程序的數據訪問對象。
清單 6. CommandLineView 對象
public class CommandLineView {
private RentABike rentaBike;
public CommandLineView() {}
public void setRentABike(RentABike rentaBike) {this.rentaBike = rentaBike;}
public RentABike getRentaBike() { return this.rentaBike; }
...
}
|
RentaBike 是具有您希望在自行車商店對象中看到的各種方法的接口:
清單 7. 接口方法
public interface RentABike {
List getBikes();
Bike getBike(String serialNo);
void setStoreName(String name);
String getStoreName();
}
|
沒有顯示 ArrayListBikeStore
,它是 BikeStore 接口的存根實現。注意,Spring 允許編寫接口,但不強制編寫接口。下面是描述該應用程序中 bean 的 XML 配置文件:
清單 8. 描述應用程序 bean 的 XML 配置文件
該上下文中有兩個 bean。commandLineView
bean 依賴于 rentaBike
bean。該應用程序通過為 rentaBike
屬性指定 rentaBike
名稱,顯式解析該依賴關系。注意,PicoContainer 自動連接這種顯式關系,Spring 也可以,但大多數用戶不使用它的自動連線選項。Spring 還允許您通過攔截器或 AOP 向外觀的任何方法添加服務。
比較
既然已經看到每種容器的哲學,下面是對每種環境的無形特性的詳細比較,比如市場份額、整體質量(fit and finish)和整體特性列表。畢竟,即使編程模型是完美的,但如果沒有文檔,或者由于缺乏社區而您必須自己支持它,那么它也不會成為一個好容器。
活動社區
Spring 有一個充滿活力的社區,和一個支持該框架的稱為 Interface21 的職業服務公司。這很重要,因為您知道您可以獲得良好的支持,公司才有動力來支持 Spring 框架。我在社區的經歷簡直太美好了。Spring 貢獻者、創始人和用戶都以杰出的內容填滿了留言板。
HiveMind 框架是一個 Apache Jakarta 項目,所以有著扎實的基礎。它有一個正在成長的萌芽社區。該框架的創始人 Howard Lewis Ship 是獨立顧問、優秀導師和不屈不撓的提倡者。但是,要利用 HiveMind 的質量幫助或者查找其 Web 站點之外的內容仍然十分困難。盡管如此,它的在線幫助似乎不錯,而且社區似乎正在成長。Hibernate 獲得了有趣的勝利,它被選中——或者更應該說,Ship 被選中——組成 TheServerSide.com 的新基礎設施,TheServerSide.com 是最重要的 Java 技術社區之一。
PicoContainer 也是一個 Apache Jakarta 項目,它似乎發展緩慢。截止本文撰稿,PicoContainer 的最后一次主要代碼發行是在 2004 年 11 月。您看不到太多有關 PicoContainer 的新文章,這有點慚愧,因為我喜歡 PicoContainer 的一些哲學。事實上,我不太確定有沒有三種開放源碼輕量級容器的空間,尤其是最近第四種輕量級容器項目 Avalon 關閉之后。
就每個社區生成的活動而言,Spring 無疑是優勝者。Interface21 的支持、奇思妙想的論壇、活躍的郵件列表以及社區的跟蹤記錄都是無與倫比的。
整體質量
社區的大小和實力通常驅動開放源碼項目的整體質量。充滿活力的社區需要更好的文檔和示例,而且它們會參與完成結尾的詳細信息。
Spring 團隊編寫了可與我見過的一些比較好的商業產品相媲美的文檔。如果這還不夠的話,您還可以找到至少五本主要 Spring 書籍和其他許多包含 Spring 內容的出版物。(我自己曾撰寫過兩本有關 Spring 的書籍,其中一本書中包括 Jolt-winning Better, Faster, Lighter Java 一章,另一本是快速入門書籍 Spring: A Developer's Notebook)。錯誤消息是專業性和描述性的。與第三方框架和 API 的集成是所有 Java 技術框架中最好的。包裝是經過深思熟慮的,不過略有多余。(它幫助我開始把一些比較小的項目劃分成模塊。)示例是優秀且有指導意義的。
與 Tapestry 一樣,HiveMind 也具有好的整體質量。Ship 自己以那些讓 HiveMind 變得簡單易用的特性而自豪,比如行準確的錯誤報告;友好簡明的 XML 語法;良好的文檔工具 HiveDoc。與用于低級詳細信息的 JavaDoc 文檔結合使用,您可以更好地描述您的應用程序(HiveMind 模塊)的高級特性,從而完善它們之間的依賴關系。
PicoContainer 編程模型感覺自然,但文檔不完整(許多方法標記看起來過時好幾個月了),而且沒有許多使用該容器的真實世界示例。有時候,我會覺得自己在獨自穿過鬼魂出沒的破屋。
但使用 PicoContainer 確實有一個主要優點。因為您配置現實世界的對象時,會得到一些編譯時錯誤檢查。實際上,該容器太小太輕了,以至于除了基本配置之外,沒有什么能出錯。PicoContainer 做了一項合理的工作。
特性
我不想過多地討論特性。如果您正在尋找許多膠水代碼來減少您的開放源碼收藏夾的集成或某特定 J2EE API,Spring 無疑是最佳選擇。HiveMind 不嘗試參與競爭。相反,它與 Spring 的服務兼容。PicoContainer 不構建而且也不嘗試構建附加物,而是選擇讓開放源碼項目為其提供服務。到目前為止,它的效果不太好。
哪一個最好?
目前,只有一個真正的答案。HiveMind 具有有趣的創新,PicoContainer 具有易于使用的模型(理論上),但社區似乎已經投票選擇了 Spring Framework。隨著時間的推移,新的容器可能會成長,HiveMind 可能不斷獲得市場份額,但目前,Spring 是您的最佳選擇。
如果您愿意冒一些險,而使用不太成熟或不太流行的容器,您可能決定實現 HiveMind(如果需要模塊級別的配置)或 PicoContainer(如果想要微小的容器)。如果需要許多膠水代碼來集成持久引擎、事務處理策略和安全性等方面,Spring 具有最完整的組件堆。但請記住:您可以在 HiveMind 容器中使用 Spring 組件。
參考資料
學習