程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用Spring框架輕松解決數據訪問和配置問題

使用Spring框架輕松解決數據訪問和配置問題

編輯:關於JAVA

如果您是一名典型的開發人員,那您必然樂意得到一個可解決數據訪問問題的解決方案,也會歡迎任何能夠簡化配置的工具。如果不是有人提出了 Spring,則對 Web 應用程序做一個總體介紹將非常困難,對於這些特定的問題更是如此。但是,天哪,我們真的需要另外一種 Web 應用程序框架嗎?在我決定撰寫一期 Geronimo 叛逆者文章,來探討 apache Geronimo 和 Spring 的交叉時,我就知道,這正是搞清所有關於 Spring 框架的傳聞的大好時機。Jeff Genender 為我解答了很多難題,我完成了這個任務。

控制反轉使配置更輕松

通過求助於 Jeff Genender、Geronimo committer 和周圍的能人,我開始了尋求有關 Spring 框架的所有問題的答案的旅程。我替那些不熟悉 Spring 的人提出了這樣的問題:Spring 究竟為何物?

稍做調查後,我了解到,Spring 是一種 Web 應用程序 API,它包含了模型-視圖-控制器(Model-VIEw-Controller,MVC)模式的實現,供那些不喜歡 Struts 的人使用。但是到底是什麼本事使其聲名顯赫?哪種至關重要的特性為此框架提供了關鍵部分?

“Spring 是一個 IoC 容器”,Jeff 解釋道,“那代表控制反轉(Inversion of Control),使您能夠注入在 XML 文件中聲明的依賴項。”

IoC 對我來說是一個新術語,因此 Jeff 解釋說,創建應用程序時通常會擁有依賴另一個對象的對象。例如,您擁有一個表示三明治制造機的對象,該對象引用了另一個對象:三明治裝填機。因此您可能擁有下面這樣的代碼(參見清單 1)。

清單1:一個樣例類

package com sandwiches;

public class SandwichMaker implements FoodMaker {

private SandwichFiller filler;

private String currentSandwich;

public void setSandwichFiller(SandwichFiller filler) {

this.filler = filler;

}

public void setNameOfSandwich(string currentSandwich) {

this.currentSandwich = currentSandwich;

}

public void makeSandwiches() {

//make sandwiches using the SandwichFiller

}

}

當然,實際的 SandwichFiller 將取決於您想要制造何種類型的三明治。因此百吉餅商店和大型三明治商店的 SandwichFiller 類實現可能會有所不同。實例化 SandwichMaker 類時,您當然可通過調用 setSandwichFiller() 方法提供 SandwichFiller 的適當實現。但隨後需要更改代碼,在新位置安裝 SandwichMaker。Spring 讓您能夠創建包含這些依賴項定義的應用程序上下文。(因此有時將此稱作依賴項注入。)

文件可能形入清單 2 所示。

清單2:ApplicationContext.XML 文件

<beans>

<bean id="bagel" class="com.sandwiches.BagelShop">

<property name="breadPreference" value="bagel" />

<property name="diameter" value="5" />

</bean>

<bean id="ccandjFiller" class="com.sandwiches.CreamCheeseAndJellyFiller">

<property name="sandwichType" ref="bagel" />

<property name="creamCheesePortion" value="60" />

<property name="jellyPortion" value="40" />

<property name="jellyFlavor" value="grape" />

</bean>

<bean id="sandwichMaker" class="com.sandwich.SandwichMaker">

<property name="sandwichFiller" ref="ccandjFiller" />

<property name="nameOfSandwich" value="Cream Cheese and Jelly" />

</bean>

</beans>

好,讓我們更仔細地觀察它一下,從底部開始。我們已告知環境,實例化 com.sandwich.SandwichMaker 類時,sandwichFiller 屬性應由標識為 ccandjFiller 的 bean 來填充。該 bean 是一個 com.sandwiches.CreamCheesAndJellyFiller,有著自己的屬性。它的 sandwichType 為 bagel,後者將 breadPreference 設置為 bagel(而不是 rye 或 bialy),並且其寬度為 5 英寸。另外,我們希望奶酪比葡萄果凍稍微多一點。

現在看來,這裡有著太多的自定義工作;如果您想將那些項都編寫到應用程序中去,則要在程序更改時進行大量的重編譯工作,或在選項中進行大量的構建工作以做出所有那些選擇。Spring 通過只更改 XML 文件而使我們能更輕松地做出更改。在此我選擇了一個比較簡單的示例,但可以想像一下,您正在配置數據源,這個 IoC 立即變得至關重要。

數據庫的優點

提到數據源,Jeff 解釋說這是另一個領域,其中 “Spring 擁有擴展了很多 J2EE(和非 J2EE)組件的優秀 API”,使開發人員更加輕松。

“在 Spring 中創建數據訪問對象相對較為簡單”,他解釋說。“使用 JDBC(或其他框架,如 Hibernate)擴展幾個 Spring 類,實現 DAO,然後在 applicationContext.xml 文件中做出聲明。此後可通過聲明的方式將這些 DAO 注入業務對象,方法是為 DAO 設定一個 setter 方法並在 Spring XML 文件中聲明業務對象。”

從交談中,我學到了如此之多的 IoC 相關知識。但不止於此:“這樣做,您就可以擺脫捕獲 SQLExceptions 的要求,並使【對數據庫的】測試與交換聲明一樣簡單。”

我明白後半部分;數據庫是一個可在 applicationContext.XML 文件中輕松設置的屬性。但它是如何使您擺脫捕獲 SQLExceptions 的要求的呢?

“Spring 將 SQLExceptions 等轉換為未檢查異常,從而隱藏了 JDBC SQL 問題。這隨後又清除了錯誤,從而使問題一目了然。這是處理數據庫異常的一種更好的方法。”

大致說來,創建 JDBC 應用程序時,如果出現問題,您將得到 SQLException。遺憾的是,該 SQLException 往往不會包含實際查找出問題所在而必需的全部信息,因為實際信息被編碼為特定於供應商的錯誤碼,您必須對其進行跟蹤。當然,由於此處設計思想的一部分是可輕松地 更改數據源,因此將智能編碼到應用程序中是不可接受的。但是,通過將數據庫交互包裝到 Spring 類中,如 JdbcTemplate,可確保將所有錯誤表達為 DataAccessException,或更重要地,表達為 DataAccessException 的十余個子類之一,包括 DataAccessResourceFailureException、DataIntegrityViolationException 和 OptimisticLockingFailureException 等。這樣您就可以更靈活地編寫應用程序。

隱藏類防止沖突

至此,我們已經介紹了大量關於 Spring 的信息,但關於 Geronimo 呢?團隊是否要做什麼特殊的工作才能將其集成到應用服務器中?

“我記得 Bruce Snyder 和 Aaron Mulder 為其 apachecon 2006 插件演示編寫了 Spring 插件,但除那之外,Spring 實際上是一個 API,因此對於 Spring,將其放入存儲庫中,它就可供所有程序使用。”

換句話說,無需執行任何特殊操作;只要 Spring 位於存儲庫中,那麼它就是可用的。

一切並沒有結束。Jeff 繼續說道,“對於其他應用服務器,人們最大的抱怨就是:需要將 Spring 放在服務器的類路徑中,而此時也將其包含在了 Web 應用程序中”—— 如果應用程序使用的 Spring 和服務器安裝的 Spring 版本不同則需進行此操作 —— “將會與當前使用的 Spring 發生沖突。這是 J2EE 應用程序的父-子、子-父類加載二分法的一部分。”

問題在於某些情況下,Java™ 2 Platform, Enterprise Edition (J2EE) 或 Java Platform, Enterprise Edition (Java EE) 在最特殊的級別啟動,尋找一個類進行實例化(在該情況下系統將使用作為應用程序一部分的類),而在其他情況下,系統使用最常規的級別(此時系統將使用作為服務器一部分的類)。結果是:您可能在應用程序的上下文中創建了一個資源,但當您嘗試訪問該資源時,服務器將在應用服務器的上下文中進行查找。

“這將使您的應用程序找不到其 Hibernate 或其他一些資源,因為它們是在一個 Spring 容器中創建而在另一個容器中訪問的。”

最初,Geronimo 開發人員通過自動隱藏某些通用類解決了此問題,比如 Spring and apache Commons Logging 類,它經常會導致此問題。但 Liferay 使情況發展到了極點,Liferay 是一種開源 JSR 168 兼容門戶(參見 參考資料 中的鏈接)。Liferay 使用 Spring,它在 .ear 文件中包含了一個 Spring 版本供其中部署的所有子應用程序使用。“我提到它們的原因在於”,Jeff 告訴我說,“我們隱藏的類加載架構在早期導致了一個問題,因為我們自動隱藏了 Spring,所以它們的 Web 應用程序無法看見 Spring 的 EAR 級版本。”

最後,Geronimo 開發人員找到了一個解決方案。“但是,我們擁有一個比大多數其他應用服務器更好的東西。許多人遇到了關於通用日志的問題。當他們在使用通用日志的容器內運行程序(如 JBoss、Tomcat 等),並且在其應用程序中包含了通用日志 JAR【文件】時,將遭遇嚴重的異常問題。”這些問題與做出初始更改前 Spring 應用程序遇到的問題相同。“它實際上是一個類加載器沖突的問題。我們遇到了一些開放式的問題,表明 Web 應用程序沒有正常運行,但實際上它們正常運行了;只需刪除通用日志,就像需為 Tomcat 和 JBoss 等刪除日志一樣。因此我們進行了大量的討論,並開始硬編碼如通用日志等模塊類。接著再繼續討論,我們找到了一種更好的聲明性方法。因而出現了隱藏類聲明。我們能在計劃文件中聲明隱藏類,您將用之來部署應用程序。”

“它運作得很好”,他繼續說道,“因此我們沒有遇到許多其他容器所具有的問題。您控制了父-子、子-父委托的類加載器。因此利用 Geronimo 可聲明應用程序只 使用其中所包含的 Spring,忽略服務器版本,反之亦然。它的另一個優點是可使用多個版本的 Spring。因此即便服務器使用 2.0 版本而您的遺留應用程序使用的是 1.x 版本,您也可確保不會發生任何沖突,並且應用程序將使用適當的版本。”

為 apache Geronimo for Spring 添加更多內容

雖然 Spring 可能已迫使團隊做出了這些更改,但它們對任何類都有用這一點可能會成為一個問題。但這並不意味著特定於 Spring 的工作有一天不會在 Geronimo 中實現。

“剛剛我在跟 Bruce Snyder 交談”,Jeff 掛斷電話後告訴我說,他接電話時我迅速地吃了點東西。“我們在談論構建或擴展一個插件,以允許您將 Spring ApplicationContexts 放入 JNDI,從而可在服務器端訪問基於 Spring 的對象。我已為一台客戶機編寫了這樣的插件,我認為它應是應用服務器的核心功能。只是要抽時間來辦這件事”,他笑著說道。

“在某種程度上我們會這樣做”,他說,“為應用程序提供基於服務器的 Spring 對象是個不錯的想法。您可以存儲希望應用程序可訪問的那些特定的 Spring 對象或對象引用。例如,如果您正在使用 Quartz,並需要容器的引用,並且通過 Spring 創建對象,則您可能需要擁有該對象的引用的 ApplicationContext 的訪問權限,因而它需要廣泛可用。將其存儲在 JNDI 中可使您的應用程序能夠訪問另一個上下文中啟動的其他 ApplicationContexts。這對於面向服務的架構 —— 和基於企業服務總線的應用程序(我以前正是在其中開發此程序)來說將是件大事。我簡單猜測,將其存放得更直接,有益於那些沒有連接到公共資源,但需要訪問這些資源的應用程序。那是存儲它的最佳方式。SOA 應用程序需要此功能。”

結束語

我們又談論了一會 Geronimo committer 和社區正努力從事的所有工作,然後我就離開了,最後,我終於明白了所有那些問題。Spring 似乎是一種很好用的框架。很明顯,當應用程序需做出任意的配置更改時,IoC 和依賴項注入使我能更輕松地進行處理,我已經浪費了太多時間去嘗試解釋 SQLExceptions,而不是去欣賞 Spring 的數據訪問方法。更重要的是,我學到了關於類加載器的知識,還搞清楚了為什麼我有時會遇到那種似乎任何方法都解決不了的錯誤,因此我從心底感激 Geronimo 的隱藏類聲明。

接下來,我准備去找人解釋一下 JavaServer Faces (JSF) 技術是怎麼回事。

關於作者

Nicholas Chase 參與過 Lucent TechnologIEs、Sun Microsystems、Oracle和 Tampa Bay Buccaneers 等眾多公司 Web 站點的開發。他曾做過高中的物理老師、低放射性廢棄物處理設備管理人員、在線科幻雜志編輯、多媒體工程師、Oracle 講師以及一家交互式通信公司的技術主管。他出版了多部著作,包括 XML Primer Plus(Sams)。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved