簡介
Spring在資源管理,DAO實現支持以及實物策略等方面提供了與Hibernate, JDO和iBATIS SQL映射的集成。 對Hibernate,Spring使用了很多IoC的方便的特性提供了一流的支持,幫助你處理很多典型的Hibernate整合的問題。所有的這些都遵守Spring通用的事務和DAO異常體系。
當您選擇使用O/R映射來創建數據訪問應用程序的時候,Spring的增加部分就會向您提供重要的支持。首先你應該了解的是,一旦你使用了Spring對O/R映射的支持,你不需要親自作所有的事情。在決定花費力氣,冒著風險建造類似的內部底層結構之前,我們都建議您考慮和利用Spring的解決方案。不管你使用的是何種技術,大部分的O/R映射支持都可以以library樣式被使用,因為所有的東西都是被設計成一組可重復利用的JavaBeans。在ApplicationContext和BeanFactory中使用更是提供了配置和部署簡單的好處,因此,這一章裡的大多數例子都是在ApplicationContext中配置。
使用Spring構建你的ORM應用的好處包括:
l 避免綁定特殊的技術,允許mix-and-match的實現策略。雖然Hibernate非常強大,靈活,開源而且免費,但它還是使用了自己的特定的API。此外有人也許會爭辯:iBatis更輕便而且在不需要復雜的O/R映射策略的應用中使用也很優秀。能夠選擇的話,使用標准或抽象的API來實現主要的應用需求,通常是更好的。尤其,當你可能會因為功能,性能或其他方面的原因而需要切換到另一個實現的時候。舉例來說,Spring對Hibernate事務和異常的抽象,以及能夠讓你輕松交換mapper和DAO對象(實現數據訪問功能)的IoC機制,這兩個特性可以讓你在不犧牲Hibernate性能的情況下,在你的應用程序中隔離Hibernate的相關代碼。處理DAO的高層次的service代碼不需要知道DAO的具體實現。這個方法可以很容易使用mix-and-match方案互不干擾地實現數據訪問層(比如在一些地方用Hibernate,一些地方使用JDBC,其他地方使用iBatis),mix-and-match有利於處理遺留下來的代碼以及利用各種技術(JDBC,Hibernate,iBatis)的長處。
測試簡單
Spring的IoC使得很容易替換掉不同的實現,Hibernate SessionFacotory的位置,datasource, 事務管理, 映射對象的實現。這樣就很容易隔離測試持久化相關代碼的各個部分。
l 普通的資源管理。Spring的application context能夠處理諸如Hibernate 的SessionFactory, JDBC的datasource,iBatis的SQLMaps配置對象以及其他相關資源的定位和配置。這使得這些配置的值很容易被管理和修改。Spring提供了有效,簡單和安全的Hibernate Session處理。一般的使用Hibernate的代碼則需要使用同一個Hibernate Session對象以確保有效和恰當地事務處理。而Spring讓我們可以很容易透明地創建和綁定一個session到當前線程;你可以使用以下兩種辦法之一:聲明式的AOP方法攔截器,或通過使用一個外部的template包裝類在Java代碼層次實現。這樣,Spring就解決了在很多Hibernate論壇上出現的使用問題。
異常包裝
Spring能夠包裝Hibernate異常,把它們從專有的,checked exception變為一組抽象的runtime exception。這樣你就可以僅僅在恰當的層處理大部分的不可恢復的異常,使你避免了很多討厭的catch/throw以及異常聲明。你還是可以在你需要的地方捕捉和處理異常。回想一下JDBC異常(包括與DB相關的方言)被轉變為同樣的異常體系,這就意味著你可以在一致的編程模型中處理JDBC操作。
l 綜合的事務管理。Spring允許你包裝你的ORM代碼,通過使用聲明式的AOP方法攔截器或者在代碼級別使用外部的template包裝類。不管使用哪一種,事務相關的語義都會為你處理,萬一有異常發生也會幫你做適當的事務操作(比如rollback)。就象我們下面要討論的一樣,你能夠使用和替換各種transaction managers,卻不會使你的Hibernate相關的代碼受到影響。更好的是,JDBC相關的代碼可以完全和Hibernate代碼integrate transactionaly。這對於處理那些沒有用Hibernate或iBatis實現的功能非常有用。
1.2.Hibernate
1.2.1.資源管理
典型的應用經常會被重復的資源管理代碼搞胡亂。很多項目嘗試創造自己的方案解決這個問題,有時會為了編程方便犧牲適當的故障處理。對於恰當的資源處理Spring提倡令人矚目的簡單的解決方案:使用templating的IoC,比如基礎的class和回調接口,或者提供AOP攔截器。基礎的類負責固定的資源處理,以及將特定的異常轉換為unchecked異常體系。Spring引進了DAO異常體系,可適用於任何數據訪問策略。
對於直接使用JDBC的情況,前面章節提到的JdbcTemplate類負責處理connection,正確地把SQLExeption變為DataAccessException體系(包括將與數據庫相關的SQL錯誤代碼變成有意義的異常類)。它同時支持JTA和JDBC事務,通過它們各自的Spring transaction managers。
Spring同樣也提供了對Hibernate和JDO的支持:一個HibernateTemplate/JdoTemplate類似於JdbcTemplate,HibernateInterceptor/JdoInterceptor,以及一個Hibernate/JDO transaction manager。主要的目的是:能夠清晰地劃分應用層次而不管使用何種數據訪問和事務技術;使應用對象之間的耦合松散。業務對象(BO)不再依賴於數據訪問和事務策略;不再有硬編碼的資源lookup;不再有難於替換的singletons;不再有自定義的服務注冊。一個簡單且堅固的方案連接了應用對象,並且使它們可重用盡可能地不依賴容器。雖然所有的數據訪問技術都能獨立使用,但是與Spring application context結合更好一些,它提供了基於XML的配置和普通的與Spring 無關的JavaBean實例。在典型的Spring app中,很多重要的對象都是JavaBeans:數據訪問template,數據訪問對象(使用template),transaction managers, 業務對象(使用數據訪問對象和transaction managers),web vIEw resolvers, web controller(使用業務對象)等等。
1.2.2.在application context中定義資源
為了避免將應用對象貼緊硬編碼的資源lookup,Spring允許你像定義普通bean一樣在application context中定義諸如JDBC DataSource,Hibernate SessionFactory的資源。需要訪問這些資源的應用對象只需要持有這些預定義實例的引用。下面的代碼演示如何創建一個JDBC DataSource和Hibernate SessionFactory:
class="org.springframework.jndi.JndiObjectFactoryBean">
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
net.sf.hibernate.dialect.MySQLDialect
……
你可以將一個JNDI定位的DataSource換為一個本地定義的如DBCP的BasicDataSource,如下面的代碼:
destroy-method="close">
當然你也可以把本地的SessionFactory換為JNDI定位的,但是如果不是在EJB上下文中,這是不需要的。(查看“容器資源 vs 本地資源”一節)
1.2.3.反轉控制:Template和Callback
對於可以成為定制的數據訪問對象或業務對象的方法來說,基本的模板編程模型看起來像下面所示的代碼那樣。對於外部對象沒有任何實現特定接口的要求,它只需要提供一個Hibernate的SessionFacotry。它可以從任何地方得到,比較適宜的方法是作為從Spring 的application context中得到的bean引用:通過簡單的setSessionFactory這個bean屬性setter。下面的代碼顯示了在application context中一個DAO的定義,它引用了上面定義的SessionFactory,同時展示了一個DAO方法的具體實現。
….
public class ProductDaoImpl implements productDao{
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public List loadProductsByCategory(final String category) {
HibernateTemplate hibernateTemplate =
new HibernateTemplate(this.sessionFactory);
return (List) hibernateTemplate.execute(
new Hi