這一章包括:
n?????
使用
DAO
模式創(chuàng)建抽象層。
n?????
使用層的父型模式簡(jiǎn)化
resource cleanup
(資源清除)代碼
n?????
用
spring
組織你的項(xiàng)目
?
理解
Hibernate
的底層將需要很長(zhǎng)一段時(shí)間才能在你的項(xiàng)目上使用。但是在
Hibernate
庫的基礎(chǔ)之外,如
SessionFactory
(會(huì)話工廠),
Session
(會(huì)話),
mapping files
(
映射文件)和
hibernate Query Language(HQL)
(
Hibernate
查詢語言),在一定高度組織一個(gè)應(yīng)用程序并不是總是那么清楚的。 你能在你的項(xiàng)目中應(yīng)用一些模式和好的經(jīng)驗(yàn)。一些好的經(jīng)驗(yàn)來自于社區(qū);而另外一些來自應(yīng)用于持久化的Java企業(yè)模式。這一章的目的就是帶給你這些。
???
寫程序有點(diǎn)像用小朋友的
alphabet blocks
(譯者注:一種表面有字母的積木)建塔。如果你是建個(gè)小塔,那么你不需要仔細(xì)關(guān)心是怎么堆的。但如果你建一個(gè)大的塔,那么你可能要站得更高,你需要稍微不同的技術(shù)設(shè)置。多一點(diǎn)計(jì)劃,多一點(diǎn)怎樣堆的技術(shù)和可能使用一些超強(qiáng)的粘合劑。
???
無論是建立玩具塔還是寫軟件都要使用好的工具和技術(shù)。因此這一章就是怎樣建立一座高塔。我們將討論一些普通的模式:
Data Access Object(DAO)
(
封裝底層數(shù)據(jù)操作
)和層的父型模式。另外,
spring
,
流行的開源項(xiàng)目將為簡(jiǎn)化你的代碼提供組織的工具。總之,這一章將給這個(gè)工具一個(gè)總的看法和怎樣簡(jiǎn)化你的
Hibernate
項(xiàng)目。
?
章節(jié)目標(biāo):
在這一章,你將完成一些幾點(diǎn):
n????????
創(chuàng)建抽象層,使用
DAO
模式集中
SQL
語句,因此簡(jiǎn)化客戶端對(duì)象使用。
n????????
使用層的父型模式改善
DAO
對(duì)象,簡(jiǎn)化
resource
cleanup
(資源清除)代碼。
n????????
使用
spring
組織和簡(jiǎn)化你的
DAO
代碼。
?
前提條件:
假設(shè)你已經(jīng)完成以下幾點(diǎn):
n????????
熟悉模式的概念。
n????????
理解
session
(會(huì)話)和
transaction
(事務(wù))的工作原理,特別是怎樣使用持久化被打開
session
(會(huì)話)鏈接的對(duì)象。
n????????
你正在尋找一種能組織大型項(xiàng)目的技術(shù)。也就是說,使用好的框架代碼將利于項(xiàng)目的以后的擴(kuò)展。
?
7.1
無處不在的
DAO
模式
大多數(shù)
Java/J2EE
開發(fā)者都或多或少熟悉
DAO
模式。它是
Sun
公司特地在
Java
藍(lán)圖中強(qiáng)調(diào)的核心模式之一,在許多
Java
書籍中都提到過。它是在使用持久化數(shù)據(jù)存儲(chǔ)的應(yīng)用程序中的采取的第一個(gè)首要模式。一般使用在使用
SQL
的應(yīng)用程序中,同樣也適用于
Hibernate
的應(yīng)用程序。
?
7.1.1
集中
HQL
DAO
模式的目的能在在一個(gè)簡(jiǎn)單問題的答案中找到:你的數(shù)據(jù)操作代碼放在哪里?如果你面對(duì)一個(gè)遺留程序而苦惱,因?yàn)檫@個(gè)程序中
SQL
代碼就像鳥槍發(fā)射那樣四處都是,而你又沒有這方面的經(jīng)驗(yàn)。其實(shí)這并沒什么。需要從新命名表中的列嗎?準(zhǔn)備好手中的槍,在整個(gè)程序中修改,以確保你沒有遺漏任何
SQL
語句。
DAO
模式鼓勵(lì)開發(fā)者集中
SQL
語句。那么怎樣才是好的
SQL
和
HQL
呢?在應(yīng)用程序中將
HQL
放在一個(gè)地方以便以后更容易維護(hù)和修改。新手可能不能很好的確定將
HQL
放在哪?他們將
HQL
放在DAO中。
Figure 7.1
顯示了
Event
和
EventDao
怎樣和數(shù)據(jù)庫互動(dòng)。
Figure 7.1
Event
和
EventDao
與數(shù)據(jù)庫互動(dòng)的圖
?
通過前面章節(jié)知道,一個(gè)健壯的對(duì)象查詢語句需要有錯(cuò)誤處理管理,事務(wù)和
resource cleanup
(資源清除)。在余下的程序中最好隱藏以上那些。例如接下來的
Hibernate
程序,使程序更容易改變
ORM
(
object/relational mapping
)
(
對(duì)象關(guān)系映射
)實(shí)現(xiàn)(例如:改變成
JDO
)1。更重要的是,這個(gè)策略簡(jiǎn)化了客戶端怎樣和持久化層互動(dòng);他們不需要知道
session
(會(huì)話),
transaction
(事務(wù))的邊界,或者在他們使用之后是否被清除。
?
DAO
也有類型
???
你能使用
DAO
兩種基本類型中的一種:
n????????
應(yīng)用級(jí)
DAO(DAO per application)
:在一個(gè)應(yīng)用中有一個(gè)中心的
DAO
對(duì)所有的實(shí)體對(duì)象添、刪、改、查。
n????????
類級(jí)
DAO(DAO per class)
:每個(gè)實(shí)體類都有自己的
DAO
,用于自身實(shí)例的添、刪、改、查。
Event
對(duì)象由
EventDao
負(fù)責(zé)。
你也可以應(yīng)用其他鏡像變量,例如使用模塊級(jí)
DAO(DAO per module)
,但是最終的選擇還是依賴于你有少個(gè)持久化對(duì)象。在有許多類的情況下,我們偏愛使用類級(jí)DAO策略。應(yīng)用級(jí)
DAO
策略會(huì)出現(xiàn)“
bloatware
”類。第二,與類級(jí)
DAO
命名對(duì)稱能更好的記憶。如果你需要找到
Event
類,你就能夠記得起它的
DAO
是
EventDao
。最后,它滿足開-關(guān)原則,原則規(guī)定類將因?yàn)閿U(kuò)充而打開,因?yàn)樾薷亩P(guān)閉。你能夠添加一個(gè)新的持久化類,而不需要修改中心的
DAO
。因此,讓我們?cè)谑纠惺褂妙惣?jí)
DAO
。
?
簡(jiǎn)單的
DAO
???
Listing 7.1
顯示了一個(gè)簡(jiǎn)單的
DAO
,它能處理滿足大多數(shù)實(shí)體需要的基本的CRUD(添、刪、改、查)業(yè)務(wù)。除了這些功能,它還有一些功能,因此客戶端對(duì)象不用擔(dān)心。
n????????
包括業(yè)務(wù)級(jí)
session
(
session per operation
)
;每個(gè)
session
(會(huì)話)都有添、刪、改、查方法。
n????????
提供一個(gè)業(yè)務(wù)級(jí)
transaction
(事務(wù))
(transaction
per operation)
。客戶端對(duì)象不用擔(dān)心開始和提交事務(wù)。
n????????
在
Hibernate2.1
中,處理捕獲和
Hibernate
拋出的預(yù)期異常,將它們變?yōu)榉穷A(yù)期異常,將不會(huì)使客戶端代碼混亂。如果你使用
Hibernate3.x
,你能夠讓沒有從新拋出的非預(yù)期異常通過。(
In Hibernate 2.x, handles catching and handling
the checked exceptions that Hibernate throws, turning them into unchecked
exceptions, which won’t clutter up client code. If you use Hibernate 3.x, you
can just let the unchecked
HibernateException
s go without rethrowing
.
)
n????????
輸入特性鮮明和明確的
DAO
;
EventDat
僅為
Event
工作,意思就是客戶端代碼不必執(zhí)行手動(dòng)的操作。(
Features strongly typed and
explicit DAOs; the
EventDao
only
works with
Event
s, meaning client code
doesn’t have to perform manual casting.
)
?
Listing 7.1
一個(gè)簡(jiǎn)單的有
添、刪、改、查方法的
EventDao
---------------------------------------------------------------------------------------------
package
?com.manning.hq.ch07;
?
import
?org.hibernate.HibernateException;
import
?org.hibernate.Session;
import
?org.hibernate.Transaction;
import
?org.apache.commons.logging.Log;
import
?org.apache.commons.logging.LogFactory;
import
?com.manning.hq.ch07.Event;
import
?com.manning.hq.ch07.HibernateFactory;
import
?java.util.List;
/**
*?DAO管理持久Evnet
*/
public
?
class
?SimpleEventDao?{
??? Log?log?
=
?LogFactory.getLog(SimpleEventDao.
class
);
??? private
?Session?session;
??? private
?Transaction?tx;
??? public
?SimpleEventDao()?{
??? ??? HibernateFactory.buildIfNeeded();
//
初始化SessionFactory。
??? }
?
??? public
?
void
?create(Event?event)?
throws
?DataAccessLayerException?{
??? ??? try
?{
??? ??? ??? startOperation();
//
打開Session和開始transaction
??? ??? ??? session.save(event);
//
保存Event。
??? ??? ??? tx.commit();
??? ??? }?
catch
?(HibernateException?e)?{
??? ??? ??? handleException(e);Rolls?back和拋出異常。
??? ??? }?
finally
?{
??? ??? ??? HibernateFactory.close(session);
??? ??? }
??? }
??? public
?
void
?delete(Event?event)?
throws
?DataAccessLayerException?{
??? ??? try
?{
??? ??? ??? startOperation();
??? ??? ??? session.delete(event);
??? ??? ??? tx.commit();
??? ??? }?
catch
?(HibernateException?e)?{
??? ??? ??? handleException(e);
??? ??? }?
finally
?{
??? ??? ??? HibernateFactory.close(session);
??? ??? }
??? }
??? public
?Event?find(Long?id)?
throws
?DataAccessLayerException{
??? ??? Event?event?
=
?
null
;
??? ??? try
?{
??? ??? ??? startOperation();
??? ??? ??? event?
=
?(Event)?session.load(Event.
class
,?id);
??? ??? ??? tx.commit();
??? ??? }?
catch
?(HibernateException?e)?{
??? ??? ??? handleException(e);
??? ??? }?
finally
?{
??? ??? ??? HibernateFactory.close(session);
??? ??? }
??? ??? return
?event;
??? }
??? public
?
void
?update(Event?event)?
throws
?DataAccessLayerException?{
??? ??? try
?{
??? ??? ??? startOperation();
??? ??? ??? session.update(event);
??? ??? ??? tx.commit();
??? ??? }?
catch
?(HibernateException?e)?{
??? ??? ??? handleException(e);
??? ??? }?
finally
?{
??? ??? ??? HibernateFactory.close(session);
??? ??? }
??? }
??? private
?
void
?handleException(HibernateException?e)?
throws
?DataAccessLayerException?{
??? ??? HibernateFactory.rollback(tx);
??? ??? throw
?
new
?DataAccessLayerException(e);
??? ??? //
?二選一,你能夠從新拋出,就像…
??? ??? //
?throw?e;
??? }
??? private
?
void
?startOperation()?
throws
?HibernateException?{
??? ??? session?
=
?HibernateFactory.openSession();
??? ??? tx?
=
?session.beginTransaction();
???? }
}
package
?com.manning.hq.ch07;
public
?
class
?DataAccessLayerException?
extends
?RuntimeException?{
//
其他的構(gòu)造函數(shù)省略。
??? public
?DataAccessLayerException(Throwable?cause)?{
??? ??? super
(cause);
??? }
}
---------------------------------------------------------------------------------------------
???
SimpleEventDao
是個(gè)極其簡(jiǎn)單的
DAO
,它有添,刪,改,查四種方法。每種方法在一個(gè)
transaction
(事務(wù)),打開和關(guān)閉一個(gè)
session
(會(huì)話)范圍內(nèi)處理業(yè)務(wù)。它是明確的,也就是說每個(gè)
Event
都有獨(dú)有的業(yè)務(wù)處理,因此客戶端類不需要再處理這些了。當(dāng)這個(gè)實(shí)現(xiàn)是簡(jiǎn)單的(以后可能隨著擴(kuò)展會(huì)變大),客戶端代碼在運(yùn)行
event
時(shí)代碼就會(huì)變得很短。(
While this implementation is simple (perhaps overly so, as we will explore
here later), it greatly shortens the client code that works with events.
)因此創(chuàng)建和查詢一個(gè)event就象下面的一樣簡(jiǎn)單:---------------------------------------------------------------------------------------------
Event?event?
=
?
new
?Event();
event.setName(
"
A?new?Event
"
);
EventDao?eventDao?
=
?
new
?EventDao();
eventDao.create(event);
Event?foundEvent?
=
?eventDao.find(event.getId());
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
正如你看到的,不需要處理凌亂的異常,這里也不需要處理
resource cleanup
(資源清除)。現(xiàn)在讓我們討論更多一些這個(gè)實(shí)現(xiàn)出現(xiàn)的問題,并且我們?cè)撛鯓犹岣咚?span lang="EN-US">
?
7.2
分析
DAO
???
我們?cè)谇懊嬲鹿?jié)練習(xí)的簡(jiǎn)單的DAO實(shí)現(xiàn)出現(xiàn)了一些問題,有些你或許已經(jīng)遇到。讓我們看一看。
?
7.2.1
boilerplate
code
(
樣板代碼)
Listing 7.1
包括許多資源管理和異常處理代碼。每個(gè)方法都有打開
session
(會(huì)話),開始事務(wù),執(zhí)行自己的商務(wù)業(yè)務(wù),提交事務(wù),事務(wù)回滾,最后關(guān)閉
session
(會(huì)話)。每個(gè)方法基本就像下面那樣:
-------------------------------------------------------------------------------
?
try
?{
???? startOperation();
???? session.save(event);
???? tx.commit();
?}?catch?(HibernateException?e)?{
???? handleException(e);
?}?finally?{
???? HibernateFactory.close(session);
?}
-------------------------------------------------------------------------------
Session.save(event)
這一行是每個(gè)方法中唯一改變的。甚至
refactoring
幾個(gè)便利的方法(譯者注:找了不少詞典,都沒有找到“
refactor
”),如
startOperation
()
和
handleException
()
,都不能完全擺脫你的樣板代碼。(
Even
refactoring out a few convenience methods,such as
startOperation()
and
handleException()
, doesn’t completely rid you
of boilerplate code
)一個(gè)
potential solution
(潛在的解決方案)就是在7.3節(jié)討論的層的父型模式。
?
7.2.2
P
otential
duplication
(
潛在的復(fù)制)
???
增加一個(gè)新的
DAO
變得很簡(jiǎn)單,只需要復(fù)制和粘貼。如果你需要其他的
DAO
,如
LocationDao
,
我們將復(fù)制和粘貼
EventDao
,然后在每個(gè)方法中改變關(guān)聯(lián)的少許幾行代碼。因?yàn)槲覀冎缽?fù)制是所有程序的惡魔之首,顯然需要做點(diǎn)事情。建立層的父型模式是非常有幫助的。
?
7.2.3
游離對(duì)象
???
因?yàn)槊總€(gè)方法都是與單一的
session
(會(huì)話)和
transaction
(事務(wù))運(yùn)作的,與
DAO
運(yùn)作的所有的
Event
是嚴(yán)格的游離對(duì)象。這個(gè)行為也許是美好的,但它不能夠利用
Hibernate
的自動(dòng)臟對(duì)象檢查和
session-level
object cache
(會(huì)話級(jí)對(duì)象緩存)。例如,假如客戶端這樣寫:
---------------------------------------------------------------------------------------------
Event?foundEvent?
=
?eventDao.find(event.getId());
foundEvent.setDuration(
30
);
eventDao.update(foundEvent);
---------------------------------------------------------------------------------------------
Find
運(yùn)行在一個(gè)
session
(會(huì)話)中,
update
運(yùn)行在另一個(gè)
session
(會(huì)話)中。它一定會(huì)運(yùn)行,但如果
find
和
update
能以某種方法共享一個(gè)
session
(會(huì)話)那才是真正的好。并且,它能更好的避免在
session
(會(huì)話)周圍的凌亂的方法署名。當(dāng)它運(yùn)作時(shí),它是難看的,因此我們不想看到下面這樣:
---------------------------------------------------------------------------------------------
Session?session?
=
?HibernateFactory.openSession();
Event?foundEvent?
=
?eventDao.find(event.getId(),?session);
foundEvent.setDuration(
30
);
eventDao.update(foundEvent,?session);?
---------------------------------------------------------------------------------------------
???
給方法增加
session
(會(huì)話)參數(shù),強(qiáng)制責(zé)任,管理和在客戶端代碼共享
session
(會(huì)話)。這樣會(huì)帶來重復(fù),復(fù)雜和潛在的錯(cuò)誤。
???
這個(gè)問題的一個(gè)潛在的解決方案是眾所周知的
Thread Local Session
模式。這個(gè)模式將在第八章介紹,因此我們不會(huì)在這里直接介紹。我們改用另外一種框架練習(xí),
spring
,它使用
Thread
Local Session
模式,在下面會(huì)有介紹。
?
7.3
層的父型模式
???
常規(guī)的
J2EE
智者認(rèn)為應(yīng)用程序被劃分成不同的層。假設(shè)你的應(yīng)用程序已經(jīng)有這些層了,當(dāng)然,依賴于你所讀的書。一些普遍的層的選擇如下:
n????????
表示層,這里是所有用戶交互和表示的代碼。
n????????
領(lǐng)域?qū)樱@里是邏輯的商務(wù)代碼。
n????????
持久層,這里是數(shù)據(jù)存儲(chǔ)操作的代碼。
???
不管你的應(yīng)用程序是否有這些層,在層中的每個(gè)對(duì)象都有某些共同的代碼能夠被固定到一個(gè)類中,這一點(diǎn)是非常普通的。這個(gè)原因出現(xiàn)了層的父型模式,每一層都有“一種類型,這種類型作為所有的層中的類型的父型”2。你能夠使用父型模式簡(jiǎn)化你的
DAO
。
???
Figure7.2
用一個(gè)簡(jiǎn)單的層次顯示了層的父型
AbstractDao
,它提供了
protected
方法,在子類中可以覆蓋和改為
public
。
???
Figure 7.2
層的父型
AbstractDao
的圖
???
下一步就是創(chuàng)建
AbstractDao
,下一節(jié)將介紹。
?
7.3.1
創(chuàng)建
AbstractDao
???
第一步是創(chuàng)建你的父型,
AbstractDao
,所有的
DAO
最后將擴(kuò)展。
Listing
7.2
顯示了類的內(nèi)容。
Listing 7.2
層的父型實(shí)現(xiàn),
AbstractDao
,它有所有
DAO
的共同的業(yè)務(wù)。
-----------------------------------------------------------------------------------------
??package?com.manning.hq.ch07;
import?org.hibernate.HibernateException;
import?org.hibernate.Query;import?org.hibernate.Session;
import?org.hibernate.Transaction;
import?java.util.List;
??
/**
*?層的父型處理所有DAO共同的運(yùn)作
*/
public?abstract?class?AbstractDao{
??? private?Session?session;
??? private?Transaction?tx;
??? public?AbstractDao()?{
??? ??? HibernateFactory.buildIfNeeded();
??? }
??? protected?void?saveOrUpdate(Object?obj){//運(yùn)作是普通的,而不是特指域對(duì)象
??? ??? try?{
??? ??? ??? startOperation();
??? ??? ??? session.saveOrUpdate(obj);
??? ??? ??? tx.commit();
??? ??? }?catch?(HibernateException?e)?{
??? ??? ??? handleException(e);
??? ??? }?finally?{
??? ??? ??? HibernateFactory.close(session);
??????? }
??? }
??? protected?void?delete(Object?obj)?{
??? ??? try?{
??? ??? ??? startOperation();
??? ??? ??? session.delete(obj);
??? ??? ??? tx.commit();
??? ??? }?catch?(HibernateException?e)?{
??? ??? ??? handleException(e);
??? ??? }?finally?{
??? ??? ??? HibernateFactory.close(session);
??? ??? }
??? }
??? protected?Object?find(Class?clazz,?Long?id){//查找基于類和id的持久化對(duì)象
??? ??? Object?obj?=?null;
??? ??? try?{
??? ??? ??? startOperation();
??? ??? ??? obj?=?session.load(clazz,?id);
??? ??? ??? tx.commit();
??? ??? }?catch?(HibernateException?e)?{
??? ??? ??? handleException(e);
??? ??? }?finally?{
??? ??? ??? HibernateFactory.close(session);
??? ??? }
??? ??? return?obj;
??? }
??? protected?List?findAll(Class?clazz)?{
??? ??? List?objects?=?null;
??? ??? try?{
??? ??? ??? startOperation();
??? ??? ??? Query?query?=?session.createQuery("from?"?+?clazz.getName());
??? ??? ??? objects?=?query.list();
??? ??? ??? tx.commit();
??? ??? }?catch?(HibernateException?e)?{
??? ??? ??? handleException(e);
??? ??? }?finally?{
??? ??? ??? HibernateFactory.close(session);
??? ??? }
??? ??? return?objects;
??? }
??? protected?void?handleException(HibernateException?e)??throws?DataAccessLayerException?{
??? ??? HibernateFactory.rollback(tx);
? ?? ? throw?new?DataAccessLayerException(e);
??? }
??? protected?void?startOperation()?throws?HibernateException?{
??? ??? session?=?HibernateFactory.openSession();
??? ??? tx?=?session.beginTransaction();
??? }
}
--------------------------------------------------------------------------------------------
????在這個(gè)Listing中,你看到了共同的CRUD方法,包括save,?find和delete方法都放入AbstractDao類中。他們是
generic和protected,因此子類能夠調(diào)用它們。這樣你的EventDao將簡(jiǎn)化。這里是一個(gè)簡(jiǎn)單的簡(jiǎn)化了的方法:
---------------------------------------------------------------------------------------------
public?????class???ImprovedEventDao???extends???AbstractDao?{
//??其他的方法省略
??? public???void??create(Event?event)??throws??DataAccessLayerException?{
??? ??? saveOrUpdate(event);
??? }
??? public??Event?find(Long?id)??throws??DataAccessLayerException?{
??? ??? return??(Event)?find(Event.?class?,?id);
??? }
}
--------------------------------------------------------------------------------------------
??? ImprovedEventDao的僅有的責(zé)任就是執(zhí)行業(yè)務(wù)和委托調(diào)用父類。樣板代碼和潛在的復(fù)制的雙重問題得到解決。當(dāng)我們?cè)黾右粋€(gè)新的實(shí)體對(duì)象時(shí),如:Locations或者Speakers,添加新的DAO--使用AbstractDao作為層的父型,將是非常迅速的。
--------------------------------------------------------------------------------------------
public?classImprovedLocationDao extendsAbstractDao?{
//其他的方法省略
??? publicvoid create(Location?location) throws??DataAccessLayerException?{
??? ??? saveOrUpdate(location);
??? }
??? publicLocation?find(Long?id)??throws??DataAccessLayerException?{
??? ??? return??(Location)?find(Location.?class?,?id);
??? }
}
---------------------------------------------------------------------------------------------
通過層的父型的介紹,剩余的問題得到解決,
DAO
與游離對(duì)象運(yùn)作。我們想在我們的方法中共享會(huì)話,甚至通過不同的
DAO
。為了做到這一點(diǎn),我們將學(xué)習(xí)一個(gè)新的流行框架,
Spring
.
?
7.4
Spring
框架
??????
我們已經(jīng)注意到已經(jīng)定義的
DAO
實(shí)現(xiàn)中的一些缺陷。復(fù)制資源管理代碼和使用業(yè)務(wù)級(jí)的
session
(
session per operation
)使解決方案會(huì)比我們需要的更加復(fù)雜,而且也沒有我們喜歡的靈活。我們一定能過編寫更好的更健壯的解決方案。幸運(yùn)的是,我們不需要擔(dān)心
---
一個(gè)優(yōu)秀的開源解決方案,
Spring
框架已經(jīng)提供給我們了。
?????? Spring
解決了比幫助我們解決
Hibernate
更多的問題。這是事實(shí),“一個(gè)輕量級(jí)的容器,允許開發(fā)者連接商務(wù)對(duì)象,
DAO
和資源就像
JDBC DataSources
和
Hibernate SessionFactories
。”
3??
它使用中心
XML
配置文件去管理資源,甚至它自身的
web MVC
框架(
Model-View-Controller
)。
Spring
是普通的框架,就是說它可以使用在許多不同的位置中。如果你不熟悉
Spring
,你也許會(huì)想我該怎樣使用它,你也許認(rèn)為他僅僅是個(gè)框架,假設(shè)用來提供某種編譯。因此我們將在這里展示。
?????? Spring
已經(jīng)被考慮成熟的分割為穩(wěn)固的集中的若干模塊,包括我們先前提到的
MVC
web
框架,
JDBC
支持,
aspect-oriented programming
(
AOP
)(
面向剖面編程
)和
ORM
模塊。這樣就允許你使用其中你需要的,而不用學(xué)習(xí)或者考慮其他的。為了我們的目的,我們將僅僅學(xué)習(xí)怎樣簡(jiǎn)化你的
Hibernate
代碼,也就是
ORM
模塊。最佳的開始的地方是模板。
??????
首先,你需要獲得
Spring
框架的副本,你可以在
www.springframework.org
找到。解壓到
applications
目錄下的
Hibernate
旁邊。
Spring
有許多可選擇的包,但為了簡(jiǎn)單,你只需要考慮一個(gè)
JAE
包,它就是
applications\spring-framework-1.2-rc2\dist\spring.jar
文件。將它加入到
build.xml
文件的
classpath
中。
-------------------------------------------------------------------------------------------------------------------------
<
property?name
=
"
spring.version
"
?value
=
"
1.2-rc2
"
/>
<
property?name
=
"
spring.lib.dir
"
??? value
=
"
${applications.dir}/spring-framework-${spring.version}
"
/>
<
path?id
=
"
spring.lib.path
"
>
<
fileset?dir
=
"
${spring.lib.dir}\dist
"
>
<
include?name
=
"
**/spring.jar
"
/>
</
fileset
>
</
path
>
<
path?id
=
"
runtime.classpath
"
>
//
?其他的?paths?省略。
<
path?refid
=
"
spring.lib.path
"
/>
<
path
>
-------------------------------------------------------------------------------------------------------------------------
??????
這個(gè)代碼配置了
Spring
使它能過在我們的示例項(xiàng)目中使用。
Hibernate3
最近已經(jīng)發(fā)布(在出版的時(shí)候),其他支持項(xiàng)目如
Spring
也跟上提供支持了。這里我們使用最新的版本。另外,因?yàn)?/span>
Spring
不得不支持
Hibernate 2
和
Hibernate 3,
一個(gè)新的包,
org.springframework.orm
。
hibernate3
已經(jīng)將它加入到
Hibernate3
的項(xiàng)目中了。接下來,讓我們看看
Spring
怎樣被使用來簡(jiǎn)化我們的示例項(xiàng)目。
?
7.4.1
在模板中是什么
?
???
Spring
給我們提供了
Hibernate
業(yè)務(wù)的模板。模板有什么,我們?yōu)槭裁葱枰看鸢妇驮谖覀兊?/span>
SimpleEventDao
中的
create
方法中。
--------------------------------------------------------------------------------------------
protected
?
void
?create(Event?event)?{
??? try
?{
??? ??? startOperation();
??? ??? session.save?(event);
??? ??? tx.commit();
??? }?
catch
?(HibernateException?e)?{
??? ??? handleException(e);
??? }?
finally
?{
??? ??? HibernateFactory.close(session);
??? }
}
--------------------------------------------------------------------------------------------
???
如果你注意了,方法中只調(diào)用一個(gè)真正的事件是:
save
()。其他的每一行,我們喜歡稱為“
excise
(稅)”。
excise
(稅)是我們?yōu)榱斯ぷ鞑坏貌蝗プ龅念~外的事情,這些事情不是真正的直接重要。它就像當(dāng)你開車去上班,駕駛的實(shí)際行動(dòng)才是重要的事情;開車庫門和倒車都是
excise
(稅)任務(wù),它可以看成同等重要,也可以忽略或者自動(dòng)完成。
??????
在程序中,
excise
(稅)是框架或者語言安全需要,你不得不編寫的代碼。一個(gè)典型的
excise
(稅)例子就是
Java
除去了內(nèi)存管理。
Spring
能夠除去
Hibernate
和
JDBC
要求之下的資源管理
excise
(稅)的一部分。
??????
一般情況下,當(dāng)你復(fù)制代碼,你能夠
refactor
出
一個(gè)方法或類。這里,因?yàn)閺?fù)制代碼是商務(wù)方法周圍的
resource?
cleanup
(資源清理),使它更加復(fù)雜。現(xiàn)在有模板可用。導(dǎo)入
Spring
提供的類:
org.springframework.orm.hibernate3.HibernateTemplate
。它包含了所有資源處理代碼以致于你僅只要寫一個(gè)重要方法就可以了。我們的
create()
方法能夠這樣寫:
----------------------------------------------------------------------------------------------------------------------------------------------------
import
?org.hibernate.Hibernate;
import
?org.hibernate.SessionFactory;
import
?org.springframework.orm.hibernate3.HibernateTemplate;
protected
?
void
?create(Event?event)?{
??? SessionFactory?sf?
=
?HibernateFactory.getSessionFactory();
??? HibernateTemplate?template?
=
?
new
?HibernateTemplate(sf);
??? template.saveOrUpdate(event);
}
-------------------------------------------------------------------------------------------------------------------------
注意我們沒有做什么:
n????????
從
SessionFactory
獲得
session
n????????
開始事物
n????????
捕獲預(yù)期異常和將他轉(zhuǎn)變?yōu)榉穷A(yù)期異常(
3.x
版本不需要,
2.x
則需要)
n????????
提交事物
n????????
將改變輸入數(shù)據(jù)庫
n????????
關(guān)閉
session
這里有許多事情我們不需要擔(dān)心,因?yàn)?/span>
HibernateTemplate
已經(jīng)照顧到了。你或許注意到
HibernateTemplate
看上去像包裹
Session
的周圍。實(shí)際上,可以把
HibernateTemplate
理解為一個(gè)“聰明”的
Session
,它知道怎樣打開,關(guān)閉和在運(yùn)行完清除。在之前默認(rèn)的情況下,它使用的是方法級(jí)事務(wù)(
transaction per method
)模式。這是非常簡(jiǎn)單的,但你將在后面看到你也能夠改事務(wù)的范圍。這里有兩個(gè)基本的方式和
Hibernatetemplate
互動(dòng):通過
convenience
mehod
(便利的方法)和重要的
callback
(回調(diào))。
?
Convenience methods
(便利的方法)
???
簡(jiǎn)單的事情將變得容易。在許多案例中,你想用
Session
(會(huì)話)做什么是非常重要的:執(zhí)行保存,更新有力對(duì)象,或者運(yùn)行
HQL
查詢。沒有一個(gè)需要禮儀來獲得完成。
HibernateTemplate
類提供了基本的方法,因此一行代碼就可以簡(jiǎn)單的調(diào)用業(yè)務(wù)。這里有一些方法的簡(jiǎn)單樣例:
---------------------------------------------------------------------------------------------
import
?com.manning.hq.ch07.Event;
import
?com.manning.hq.ch07.HibernateFactory;
import
?org.springframework.orm.hibernate3.HibernateTemplate;
import
?java.util.List;
SessionFactory?sessionFactory?
=
HibernateFactory.getSessionFactory();
//
?創(chuàng)建連接?SessionFactory?的模板
HibernateTemplate?template?
=
new
?HibernateTemplate(sessionFactory);
Event?event1?
=
?
new
?Event();
event1.setName(
"
Event?1
"
);
Event?event2?
=
?
new
?Event();
event2.setName(
"
Event?2
"
);
??? try
?{
??? ??? template.save?(event1);???
//
?在一個(gè)事務(wù)中保存?event
??? ??? template.save?(event2);
//
?加載一個(gè)?event
??? ??? Event?obj?
=
?(Event)?template.load(Event.
class
,?event1.getId());
??? ??? System.out.println(
"
Loaded?the?event
"
?
+
?obj.getName());
//
?找到所有的?event
??? ??? List?events?
=
?(List)?template.find(
"
from?Event
"
);
??? ??? System.out.println(
"
#?of?Events?
"
?
+
?events.size());
??? }?
finally
?{
??? ??? template.delete(event1);?
//
?刪除一個(gè)?event
??? ??? template.delete(event2);
??? }
---------------------------------------------------------------------------------------------
convenience
methods
(
便利的方法)是有代表性的正確的命名,就像
Session
(會(huì)話)中的方法一樣。他們能被
session
(會(huì)話)作為
one-for-one
(一對(duì)一)復(fù)位直接調(diào)用,沒有任何雜亂的
resource cleanup
(資源清除)代碼障礙。
?
Callback
(回調(diào))
???
復(fù)雜的事情可能有好處。不是所有的在單個(gè)
transaction
(
事務(wù))中的單個(gè)
query
(查詢)能夠輕松的減少業(yè)務(wù)。在這些業(yè)務(wù)中,
spring
提供了
Callback
接口。它允許你在將要執(zhí)行的模板中編寫
callback
方法。例如,如果你想構(gòu)建一個(gè)復(fù)雜的
query
(查詢),更新一些數(shù)據(jù),然后保存,所有的都在一個(gè)業(yè)務(wù)中:
-------------------------------------------------------------------------------------------
import
?org.hibernate.HibernateException;
import
?org.springframework.orm.hibernate3.HibernateCallback;
import
?java.sql.SQLException;
import
?org.hibernate.Query;
import
?java.util.List;
import
?java.util.Iterator;
import
?com.manning.hq.ch07.Event;?
template.execute(
new
?HibernateCallback()?{
??? public
?Object?doInHibernate(Session?session)?
throws
?HibernateException,?SQLException?{
?? ??? Query?query?
=
?session.createQuery(
"
from?Event
"
);
??? ??? query.setMaxResults(
2
);
??? ??? List?events?
=
?query.list();
??? ??? for
?(Iterator?it?
=
?events.iterator();?it.hasNext();)?{
??? ??? ??? Event?event?
=
?(Event)?it.next();
??? ??? ??? event.setDuration(
60
);
??? ??? }
??? ??? return
?
null
;
??? }
})?;
---------------------------------------------------------------------------------------------
這里,
Callback
接口使用了匿名內(nèi)部類,
HibernateCallback
,定義了一個(gè)單一的方法,
doInHibernate()
。你可以編寫方法主體,然后提交
HibernateCallback
對(duì)象給模板,然后執(zhí)行。模板處理資源管理代碼,讓你只需要編寫任務(wù)的
query
(查詢)邏輯。
?
7.4.2
Beans
和 它們的
factories
(工廠)
你已經(jīng)看到能夠程序化使用
Spring
去減少
resource
cleanup
(資源清除)代碼。另外i,它能過更好的組織項(xiàng)目。
Spring
的慣例的說法是“輕量級(jí)”容器。它勝任執(zhí)行和配置簡(jiǎn)單的
JavaBeans
。它基本扮演構(gòu)建和配置你應(yīng)用程序中的
beans
的工廠角色。意思是它能夠被使用去配置大多數(shù)現(xiàn)存的
architectures
(框架)和庫,包括
Hibernate
。
?
中心的配置文件
???
在這一點(diǎn)上,你將通過組合使用
hibernate.cfg.xml
文件(
declaratively
(聲明性的
))和使用靈活的編程方式,如HibernateFactory來配置Hibernate。Spring提供了另外一個(gè)方法整體聲明配置Hibernate。使用Spring的最大好處就是你能夠減少編程配置需要的元素。
?
Spring
能夠讀用一般配置格式編寫的
XML
文件。
XML
指定了怎樣連接不同對(duì)象,包括
DataSource
(數(shù)據(jù)源),
SessionFactory
和所有的
DAOs
。一旦你配置了文件,你就能夠?qū)⑺鳛椴檎?/span>
DAOs
的中心“票據(jù)交換所”使用。例如,在
classpath
的
root
(根部)創(chuàng)建一個(gè)叫
applicationContext.xml
文件。就像
listing7.3
所顯示那樣。
?
listing7.3 ApplicationContext.xml
,定義了
DataSource
(數(shù)據(jù)源),
SessionFactory
和
DAO
-------------------------------------------------------------------------------
??
<?
xml?version
=
"
1.0
"
?encoding
=
"
UTF-8
"
?>
? <!
DOCTYPE?beans?PUBLIC
??? ? "
-//SPRING//DTD?BEAN//EN
"
??? ? "
http://www.springframework.org/dtd/spring-beans.dtd
"
>
??? <
beans
>
??? ??? <
bean?id
=
"
dataSource
"
class
=
"
org.apache.commons.dbcp.BasicDataSource
"
????? ??? destroy
-
method
=
"
close
"
>
???①
??? ??? <
property?name
=
"
driverClassName
"
>
??? ??? ??? <
value
>
com.mysql.jdbc.Driver
</
value
>
??? ??? </
property
>
??? ??? <
property?name
=
"
url
"
>
??? ??? ??? <
value
>
jdbc:mysql:
//
localhost/events_calendar</value>
??? ??? </
property
>
??? ??? <
property?name
=
"
username
"
>
??? ??? ??? <
value
>
root
</
value
>
??? ??? </
property
>
??? ??? <
property?name
=
"
password
"
>
??? ??? ??? <
value
></
value
>
??? ??? </
property
>
??? ??? </
bean
>
??? ??? <
bean?id
=
"
factory
"
class
=
"
org.springframework.orm.hibernate3.LocalSessionFactoryBean
"
>
?②
??? ??? <
property?name
=
"
mappingResources
"
>
??? ??? ??? <
list
>
??? ??? ??? ??? <
value
>
com
/
manning
/
hq
/
ch07
/
Event.hbm.xml
</
value
>
??? ??? ??? ??? <
value
>
com
/
manning
/
hq
/
ch07
/
Location.hbm.xml
</
value
>
??? ??? ??? </
list
>
??? ??? </
property
>
??? ??? <
property?name
=
"
hibernateProperties
"
>
??? ??? ??? <
props
>
??? ??? ??? ??? <
prop?key
=
"
hibernate.dialect
"
>
org.hibernate.dialect.MySQLDialect
</
prop
>
??? ??? ??? ??? <
prop?key
=
"
hibernate.show_sql
"
>
false
</
prop
>
??? ??? ??? </
props
>
??? ??? </
property
>
??? ??? <
property?name
=
"
dataSource
"
>
???③
??? ??? ??? <
ref?bean
=
"
dataSource
"
/>
??? ??? </
property
>
??? ??? </
bean
>
??? ??? <
bean?id
=
"
eventDao
"
class
=
"
com.manning.hq.ch07.EventSpringDao
"
>
????④
??? ??? <
property?name
=
"
sessionFactory
"
>
?????⑤
??? ??? ??? <
ref?bean
=
"
factory
"
?
/>
??? ??? </
property
>
??? ??? </
bean
>
??? </
beans
>
-------------------------------------------------------------------------------
listing7.3
解釋
①
???
配置一個(gè)基本的數(shù)據(jù)源,它使用由
Hibernate
發(fā)布的
Apache Commons database connection
pool (DBCP)
。
②??????
配置一個(gè)
SessionFactory
,構(gòu)建在
Spring
SessionFactory
wrapper, LocalSessionFactoryBean
。當(dāng)
Spring
讀取這個(gè)文件時(shí),它就構(gòu)建一個(gè)
SessionFactory
。
SessionFactory
存儲(chǔ)在
Key factory
。
③???????
連接
SessionFactory
和數(shù)據(jù)源。
④???????
配置你的
EventSpringDao
和
eventDao
。
⑤???????
連接
DAO
和
session factory
。他允許
DAO
打開
session
和發(fā)布
queries
。
-------------------------------------------------------------------------------------------------------------------------
Listing 7.3
中
XML
配置文件列舉了所有能夠經(jīng)常改變?cè)敿?xì)內(nèi)容。它完成了許多與
hibernate.cfg.xml
所作的相同的事情,也為我們構(gòu)建了
SessionFactory
,這一點(diǎn)將在下一節(jié)看到。
?
構(gòu)建
AppicationContext
???
你剛剛創(chuàng)建的
applicationContext.xml
詳細(xì)的描述了怎樣構(gòu)建
session
工廠。它基本上可以一對(duì)一的替換你所看到的
HibernateFactory
使用的
hibernate.cfg.xml
。它定義了通常在
hibernate.cfg.xml
中的屬性和映射文件。在我們先前的示例代碼中,你需要構(gòu)建
SessionFactory
,或者通過你的
EventDao
對(duì)象連接
SessionFactory
。
Spring
顛覆了這個(gè)概念。
Spring
為你構(gòu)建了
EventDao
,你需要詢問
EventDao
的首選項(xiàng),就像:
---------------------------------------------------------------------------------------------
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import
?com.manning.hq.ch07.Event;
ClassPathXmlApplicationContext?ctx?
=
?
new
ClassPathXmlApplicationContext(
"
applicationContext.xml
"
);
EventSpringDao?eventDao?
=
(EventSpringDao)?ctx.getBean(
"
eventDao
"
,?EventSpringDao.
class
);
Event?event?
=
?
new
?Event();
eventDao.saveOrUpdate(event);
--------------------------------------------------------------------------------------------
ClasspathXmlApplicationContext
看上去
在
classpath
中,因?yàn)榕渲梦募拿衷?/span>
instruction
中已提供(
The
ClasspathXmlApplicationContext
looks in the classpath for the name of the
configuration file provided in the instructions.
)在這個(gè)案例中,
applicationContext.xml
在
classpath
的
root
(根)。你能夠從
application context
通過名字請(qǐng)求
bean
。
getBean
()方法有兩個(gè)參數(shù):
bean
的名字(
eventDao
),你期望的類的類型(
EventSpringDao
)。
在此之下,
Spring
構(gòu)建了
SessionFactory
并將所有的
Bean
連接在一起。我們更早的認(rèn)識(shí)到
Spring
與
Javabean
一起工作。所有的在
applicationContext.xml
文件中的
<bean>
元素都需要
JavaBean
。這包括了象下面的
EventSpringDao
。
-------------------------------------------------------------------------------------------------------------------------
public
?
class
?EventSpringDao?
extends
?AbstractSpringDao{
??? public
?EventSpringDao(){}
??? public
?Event?find(Long?id){
??? ??? return
?(Event)?
super
.find(Event.
class
,?id);
??? }
??? //
?Other?methods?excluded
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
????????
另外更早的認(rèn)識(shí)到的好處是,
Spring
提供了
org.springframework.orm.hibernate3.support.HibernateDaoSupport
,
應(yīng)用
Dao
層的父型。她管理了
SessionFactory
和一些有用的方法去處理
Session
,
Logging
和
HibernateTemplate
。這有這些方法的示例:
-------------------------------------------------------------------------------
public
?
abstract
?
class
?HibernateDaoSupport?
implements
?InitializingBean?{
??? protected
?
final
?Log?logger;
??? private
?HibernateTemplate?hibernateTemplate;
??? public
?
final
?
void
?setSessionFactory(SessionFactory?sessionFactory);
??? public
?
final
?SessionFactory?getSessionFactory();
??? public
?
final
?
void
?setHibernateTemplate(HibernateTemplate?hibernateTemplate);
??? public
?
final
?HibernateTemplate?getHibernateTemplate();
? ??? ??? ????? ??? ??? ??? ??? ??? ?? ??? ??? protected
?
final
?Session?getSession()?
throws? ??? DataAccessResourceFailureException,?IllegalStateException;
??? protected?final?void?closeSessionIfNecessary(Session?session);
}
-----------------------------------------------------------------------------------
他提供了一些基本的方法,但我們選擇重寫
HibernateDaoSupport
對(duì)象,為了
提供更多的便利方法。
Listing7.4
顯示了改變的類。
Listing
7.4
你的應(yīng)用的層的父型
DAOs
--------------------------------------------------------------------------------------------
package
?com.manning.hq.ch07;
import
?java.util.List;
import
?org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public
?
abstract
?
class
?AbstractSpringDao?
extends
?HibernateDaoSupport{
??? public
?AbstractSpringDao()?{?}
??? protected
?
void
?saveOrUpdate(Object?obj)?{
??? ??? getHibernateTemplate().saveOrUpdate(obj);
??? }
??? protected
?
void
?delete(Object?obj)?{
??? ??? getHibernateTemplate().delete(obj);
??? }
??? protected
?Object?find(Class?clazz,?Long?id)?{
??? ??? return
?getHibernateTemplate().load(clazz,?id);
??? }
??? protected
?List?findAll(Class?clazz)?{
??? ??? return
?getHibernateTemplate().find(
"
from?
"
?
+
?clazz.getName());
??? }
}
------------------------------------------------------------------
重點(diǎn)注意的是
AbstractSpringDao
使用它的父類
sessionFactory
成員。
HibernateDaoSupport
提供了
getter
和
setter
方法,
Spring
使用
setter
方法去連接
SessionFactory
。從
applicationContext
.xml
文件中調(diào)用這些行:
-------------------------------------------------------------------------------
<
bean?id
=
"
eventDao
"
?
class
=
"
com.manning.hq.ch07.EventSpringDao>
??? <
property?name
=
"
sessionFactory
"
>
??? ??? <
ref?bean
=
"
factory
"
?
/>
??? </
property
>
</
bean
>
------------------------------------------------------------------
這是調(diào)用
setSessionFactory
()
的片斷,通過我們配置的
SessionFactory
,我們叫它為工廠。你所看到的
AbstractSpringDao
是由
AbstractDao
進(jìn)化而來,你可以從
find()
方法中完整的除去大多數(shù)資源管理代碼。
HibernateTemplate
和
HibernateDaoSupport
替代了被控制的一切。
?
創(chuàng)建注冊(cè)(
Creating a registry
)
我們最終是為了將所有集中到一起并創(chuàng)建中心的注冊(cè),開發(fā)者能夠使用它直接獲得參數(shù)給
DAO
和
SessionFactory
。通過單一的類,
CalendarRegistry
,你能確保將來開發(fā)有一個(gè)顯示的,單一的,強(qiáng)壯類型的類來使用,不需要知道類的詳細(xì)內(nèi)部機(jī)制。
Figure 7.3
顯示了怎樣將所有集中到一起。
使用
Spring
,你獲得了配置的好處,允許你輕松的交換數(shù)據(jù)資源,數(shù)據(jù)庫和添加新的對(duì)象成員。
Listing7.5
就是
CalendarRegistry
。
?
Figure
7.3 CalendarRegistry
圖表,獲得參數(shù)到
EventDao
?
Listing
7.5
CalendarRegistry
,
組織
Dao
的中心的類
-------------------------------------------------------------------------------------------------------------------------
package
?com.manning.hq.ch07;
import
?org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import
?org.hibernate.SessionFactory;
public
?
class
?CalendarRegistry?{
??? private
?
static
?ApplicationContext?ctx;
??? static
?{
??? ??? ctx?
=
?
new
?ClassPathXmlApplicationContext(
"
applicationContext.xml
"
);
??? }
??? private
?CalendarRegistry()?{}
??? public
?
static
?SessionFactory?getSessionFactory()?{
??? ??? return
?(SessionFactory)?ctx.getBean(
"
factory
"
,?SessionFactory.
class
);
??? }
??? public
?
static
?EventSpringDao?getEventDao()?{
??? ??? return
?(EventSpringDao)ctx.getBean(
"
eventDao
"
,?EventSpringDao.
class
);
??? }
}
-------------------------------------------------------------------------------------------------------------------------
正如你所見,
CalendarRegistry
是單例模式,但是因?yàn)樗澈笫?/span>
Spring
,你能夠輕松的實(shí)現(xiàn)底層的交換。它從
classpath
中裝載單一的靜態(tài)的
ApplicationContext
,然后使用它獲取參數(shù)。現(xiàn)在客戶端對(duì)象能夠在項(xiàng)目中任何地方獲得參數(shù)給
EventDao
,不需要知道關(guān)于
Spring
做了什么。
-------------------------------------------------------------------------------------------------------------------------
EventSpringDao?eventDao?
=
?CalendarRegistry.getEventDao();
eventDao.saveOrUpdate(event);
--------------------------------------------------------------------------------------------
?
更多的
Spring
工具
就像你所見,使用
Spring
能夠最大限度的簡(jiǎn)化
Hibernate
的資源管理代碼。我們顯示了兩個(gè)你能夠使用的包含的級(jí)別。
HibernateTemplate
能夠被嵌入你的
DAO
中,或者使用
Spring
的輕量級(jí)容器去管理
DAO
。
???
Spring is a fairly straightforward framework, but we haven’t scratched the
surface of what it can do here.
(
Spring
還算一個(gè)直接的框架,但我們沒有就它能在這做什么過多的糾纏)
Spring
也支持事務(wù)
API
管理框架,
AOP
框架,一個(gè)
RuntimeException
框架,能夠攔截?cái)?shù)據(jù)庫發(fā)出的大多數(shù)遲鈍的
SQLException
,將它轉(zhuǎn)變成更顯而易見和包羅萬象的
exception
。更多的信息,請(qǐng)查看實(shí)在又全面的
Spring
文檔。
?
7.5
總結(jié)
這一章的焦點(diǎn)在于提高組織你的應(yīng)用程序代碼。我們集中了
HQL
,使用了
DAO
模式。我們通過加入其它的模式更提高了初始實(shí)現(xiàn),層的父型,它允許增加更多的DAO,不需要復(fù)制過多的代碼到項(xiàng)目中新添加的對(duì)象成員。
???
這一章也探索了怎樣使用
Spring
,另一個(gè)流行的開源項(xiàng)目,管理
Hibernate
需要的
boilerplate
(樣板)資源管理代碼。
Spring
提供了標(biāo)題選項(xiàng),
HibernateTemplate
,
pluggable
,
ApplicationContext
。增加一個(gè)
CalendarRegistry
,
它提供了方法使用
Spring
獲得項(xiàng)目中的參數(shù),不再需要去包含一個(gè)“單塊集成電路”了。
?
1
Hibernate
如此優(yōu)秀,為什么還要用別的?在現(xiàn)實(shí)中,轉(zhuǎn)變
ORM
實(shí)現(xiàn)并不是微不足道的,
DAO
是容易產(chǎn)生漏洞的,提取那樣做的話就會(huì)有問題,將不能從應(yīng)用程序中完全隱藏
Hibernate
。(
DAOs are leaky enough
abstractions that doing so probably won’t completely hide Hibernate from the
application.
)。
因此不需要放太多的精力去密封
DAO
層,在以后為了可能的某種目的要轉(zhuǎn)變
ORM
實(shí)現(xiàn)。
?
2
選自
《
Patterns
of Enterprise Application Architecture
》
,
作者:
Martin Fowler(Addision-Wesley
專家,
2003
)
?
3
選自在線文章“
Data
Access with Spring Framework
”,作者:
Juergen Hoeller
,
2003
年
7
月;
http://hibernate.bluemars.net/110.html
。
posted on 2005-12-21 22:21
千山鳥飛絕 閱讀(10516)
評(píng)論(6) 編輯 收藏 所屬分類:
Hibernate