Figure 5. Encapsulating the business logic with a POJO façade
表示層調(diào)用POJO facade, POJO facade 調(diào)用業(yè)務(wù)對(duì)象。和EJB容器截獲EJB facade方式一樣,AOP通過(guò)“攔截機(jī)”來(lái)截獲POJO facade,并驗(yàn)證調(diào)用者的權(quán)限,然后開(kāi)始提交業(yè)務(wù)處理或讓該業(yè)務(wù)循環(huán)等待。
通過(guò)在應(yīng)用程序服務(wù)器外部開(kāi)發(fā)和調(diào)試業(yè)務(wù)邏輯,對(duì)POJO facade的開(kāi)發(fā)可以變的很簡(jiǎn)單,同時(shí)還可以獲得許多EJB中會(huì)話Bean的好處,比如聲明事務(wù)處理和安全。關(guān)鍵是,你可以少寫(xiě)點(diǎn)代碼。你可以避免寫(xiě)數(shù)據(jù)傳輸對(duì)象類,因?yàn)镻OJO facade可以將對(duì)象域直接反饋給表示層;你可以使用依賴注射的方式來(lái)將應(yīng)用程序組裝起來(lái),而不用在為JNDI寫(xiě)查找代碼了。
然而,有些時(shí)候不能那用POJO facade,比如它不能參與到遠(yuǎn)程客戶端建立的分布式事務(wù)處理。
暴露模型域模式
使用facade的一個(gè)缺點(diǎn)是你必須寫(xiě)額外的代碼,而且負(fù)責(zé)將對(duì)象域返回給表示層的代碼很容易出錯(cuò)。如果表示層設(shè)法調(diào)用某個(gè)對(duì)象,而業(yè)務(wù)層卻沒(méi)有提供該對(duì)象,也會(huì)增加runtime error出現(xiàn)的機(jī)會(huì)。如果你用JDO , Hibernate或者EJB3,則可以避免這種問(wèn)題,方法是:將模型域(session區(qū)域)暴露給表示層,再將相應(yīng)的對(duì)象域(存儲(chǔ)對(duì)象的區(qū)域)返回給表示層,根據(jù)表示層在對(duì)象域之間的操作關(guān)系,持久層來(lái)導(dǎo)入相應(yīng)的對(duì)象。(也就是把session區(qū)域給表示層,然后分析它需要的對(duì)象,再讓持久層去加載這些對(duì)象)這就是所謂的lazy loading 技術(shù)。
Figure 6. Using an exposed domain model
用這種實(shí)現(xiàn)途徑的一個(gè)重要的好處是,業(yè)務(wù)層不需要知道哪些對(duì)象需要調(diào)用,也不用知道那些需要返回給表示層。盡管這挺起來(lái)很簡(jiǎn)單,但是你會(huì)發(fā)現(xiàn)一些缺點(diǎn)。這會(huì)增加表示層的復(fù)雜度,因?yàn)槟惚仨毺幚韺?duì)數(shù)據(jù)庫(kù)的連接。而且在基于Web的應(yīng)用程序中,事務(wù)處理管理也要非常小心,因?yàn)樵诒硎緦訉?shù)據(jù)反饋給瀏覽器之前,事務(wù)處理的數(shù)據(jù)必須保持正確。
決策3:訪問(wèn)數(shù)據(jù)庫(kù)
無(wú)論你怎樣對(duì)業(yè)務(wù)邏輯怎樣的組織和封裝,最終你還是要從數(shù)據(jù)庫(kù)中取數(shù)據(jù)出來(lái)。在經(jīng)典的J2EE應(yīng)用程序中,你有2個(gè)選擇:JDBC——這個(gè)需要很多的底層代碼;或者實(shí)體Bean——這個(gè)用起來(lái)非常困難,而且缺少重要特征。相比來(lái)說(shuō),使用輕量級(jí)構(gòu)架令人高興的事情之一就是:你有一些新的而且更有力的方法去訪問(wèn)數(shù)據(jù)庫(kù),而且這種方法可以顯著的減少訪問(wèn)數(shù)據(jù)庫(kù)的代碼。讓咱們來(lái)進(jìn)一步研究。
直接用JDBC會(huì)有什么問(wèn)題
最近突然出現(xiàn)了對(duì)象/關(guān)系 映射構(gòu)架(比如JDO和Hibernate) 和SQL映射構(gòu)架(比如iBATIS)這些不是憑空出現(xiàn)的。相反,他們是在JAVA 聯(lián)盟在JDBC屢造挫折之后才出現(xiàn)的。為了了解新構(gòu)架出現(xiàn)的原因,這里咱們回顧一下直接使用JDBC會(huì)出現(xiàn)的問(wèn)題。在許多程序中直接使用JDBC不是一個(gè)好的選擇,主要有以下三個(gè)原因:。 開(kāi)發(fā)和維護(hù)SQL非常的困難而且耗費(fèi)時(shí)間——一些開(kāi)發(fā)者發(fā)現(xiàn)要寫(xiě)龐大而且復(fù)雜的SQL語(yǔ)句非常的困難。反映數(shù)據(jù)庫(kù)變化的SQL語(yǔ)句會(huì)變得非常耗時(shí)。你必須小心的考慮犧牲可維護(hù)性是否值得。。 用SQL會(huì)使移植性變的很差——因?yàn)樾枰獢?shù)據(jù)庫(kù)的特殊SQL語(yǔ)句。如果一個(gè)程序和多個(gè)數(shù)據(jù)庫(kù)有關(guān)系,那么你就要寫(xiě)多個(gè)版本的SQL語(yǔ)句,這使得可維護(hù)性變變成噩夢(mèng)。。 直接寫(xiě)JDBC代碼要會(huì)非常耗時(shí),而且容易出錯(cuò)。你必須寫(xiě)很多的樣板代碼去獲得連接,創(chuàng)建和初始化適當(dāng)?shù)穆暶鳎€要用精確的聲明去清理連接。而且你還要寫(xiě)代碼去將JAVA 對(duì)象映射到SQL聲明。由于要無(wú)奈的去寫(xiě),JDBC代碼很容易出錯(cuò)。
如果你的程序必須直接運(yùn)行SQL語(yǔ)句的話,那前面兩個(gè)問(wèn)題是無(wú)法避免的。有時(shí)候?yàn)榱双@得好的性能,必須要全力的寫(xiě)SQL語(yǔ)句,包括供應(yīng)商提供的那些特殊東西。由于許多業(yè)務(wù)上的原因,持久層可能會(huì)產(chǎn)生混亂的SQL語(yǔ)句,為了防止這種情況,DBA可能要求你的程序來(lái)完全控制SQL語(yǔ)句的執(zhí)行。通常,團(tuán)隊(duì)買進(jìn)的關(guān)系型數(shù)據(jù)庫(kù)過(guò)于龐大,以至于應(yīng)用程序工作時(shí)會(huì)出現(xiàn)一些和數(shù)據(jù)庫(kù)有關(guān)的瑣碎事務(wù)。根據(jù)“iBATIS in Action”的作者說(shuō)這里會(huì)有一種情況出現(xiàn):“數(shù)據(jù)庫(kù)或者SQL語(yǔ)句本身存在的時(shí)間比程序代碼存在的時(shí)間還要長(zhǎng),或者同一段SQL語(yǔ)句或數(shù)據(jù)庫(kù)有多個(gè)程序的版本。有些情況下,程序已經(jīng)用另外一種語(yǔ)言重寫(xiě)了,但是SQL語(yǔ)句和數(shù)據(jù)庫(kù)卻沒(méi)有太大的改變?!?如果直接使用SQL弄的你筋疲力盡,那么很幸運(yùn),這里有一種直接執(zhí)行SQL語(yǔ)句的構(gòu)架,它可比用JDBC要容易多了。當(dāng)然了,這就是iBATIS.
使用iBATIS
我開(kāi)發(fā)過(guò)的所有企業(yè)JAVA應(yīng)用程序,都是直接執(zhí)行SQL語(yǔ)句的。早期的程序是執(zhí)行特定的SQL語(yǔ)句的,后來(lái)是用持久層構(gòu)架再用少量的SQL語(yǔ)句構(gòu)成的。一開(kāi)始我直接用JDBC來(lái)執(zhí)行SQL語(yǔ)句,但是后來(lái),我經(jīng)常寫(xiě)一些小的構(gòu)架去完成JDBC中那些比較無(wú)聊的部分。我也用過(guò)一段Spring的JDBC類,這些類除去了JDBC中的許多樣板代碼。但是無(wú)論是我自己寫(xiě)的構(gòu)架還是使用Spring的類,在Java類映射到SQL語(yǔ)句的時(shí)候都會(huì)存在問(wèn)題,這就是我為什么那么高興的加入iTATIS 那邊的原因了。
iBATIS 不僅將應(yīng)用程序完全的與“數(shù)據(jù)庫(kù)連接”、具體的SQL語(yǔ)句隔絕開(kāi)來(lái),更實(shí)現(xiàn)了通過(guò)XML描述文檔來(lái)將JavaBean 映射到SQL語(yǔ)句。它用Java bean 內(nèi)省機(jī)制來(lái)將“道具bean(bean properties)”映射為相應(yīng)的數(shù)據(jù)庫(kù)語(yǔ)句占位符,而且它可以將ResultSet后的結(jié)果構(gòu)造為bean.它還可以通過(guò)數(shù)據(jù)庫(kù)生成主鍵,自動(dòng)加載相關(guān)的對(duì)象、實(shí)現(xiàn)緩存和lazy loading.這樣,iBATIS 就除去了許多執(zhí)行SQL語(yǔ)句帶來(lái)的苦差。通過(guò)編輯XML描述文檔和調(diào)用少量的iBATIS的API,代替了寫(xiě)大量的JDBC底層代碼。
表示層調(diào)用POJO facade, POJO facade 調(diào)用業(yè)務(wù)對(duì)象。和EJB容器截獲EJB facade方式一樣,AOP通過(guò)“攔截機(jī)”來(lái)截獲POJO facade,并驗(yàn)證調(diào)用者的權(quán)限,然后開(kāi)始提交業(yè)務(wù)處理或讓該業(yè)務(wù)循環(huán)等待。
通過(guò)在應(yīng)用程序服務(wù)器外部開(kāi)發(fā)和調(diào)試業(yè)務(wù)邏輯,對(duì)POJO facade的開(kāi)發(fā)可以變的很簡(jiǎn)單,同時(shí)還可以獲得許多EJB中會(huì)話Bean的好處,比如聲明事務(wù)處理和安全。關(guān)鍵是,你可以少寫(xiě)點(diǎn)代碼。你可以避免寫(xiě)數(shù)據(jù)傳輸對(duì)象類,因?yàn)镻OJO facade可以將對(duì)象域直接反饋給表示層;你可以使用依賴注射的方式來(lái)將應(yīng)用程序組裝起來(lái),而不用在為JNDI寫(xiě)查找代碼了。
然而,有些時(shí)候不能那用POJO facade,比如它不能參與到遠(yuǎn)程客戶端建立的分布式事務(wù)處理。
暴露模型域模式
使用facade的一個(gè)缺點(diǎn)是你必須寫(xiě)額外的代碼,而且負(fù)責(zé)將對(duì)象域返回給表示層的代碼很容易出錯(cuò)。如果表示層設(shè)法調(diào)用某個(gè)對(duì)象,而業(yè)務(wù)層卻沒(méi)有提供該對(duì)象,也會(huì)增加runtime error出現(xiàn)的機(jī)會(huì)。如果你用JDO , Hibernate或者EJB3,則可以避免這種問(wèn)題,方法是:將模型域(session區(qū)域)暴露給表示層,再將相應(yīng)的對(duì)象域(存儲(chǔ)對(duì)象的區(qū)域)返回給表示層,根據(jù)表示層在對(duì)象域之間的操作關(guān)系,持久層來(lái)導(dǎo)入相應(yīng)的對(duì)象。(也就是把session區(qū)域給表示層,然后分析它需要的對(duì)象,再讓持久層去加載這些對(duì)象)這就是所謂的lazy loading 技術(shù)。
Figure 6. Using an exposed domain model
用這種實(shí)現(xiàn)途徑的一個(gè)重要的好處是,業(yè)務(wù)層不需要知道哪些對(duì)象需要調(diào)用,也不用知道那些需要返回給表示層。盡管這挺起來(lái)很簡(jiǎn)單,但是你會(huì)發(fā)現(xiàn)一些缺點(diǎn)。這會(huì)增加表示層的復(fù)雜度,因?yàn)槟惚仨毺幚韺?duì)數(shù)據(jù)庫(kù)的連接。而且在基于Web的應(yīng)用程序中,事務(wù)處理管理也要非常小心,因?yàn)樵诒硎緦訉?shù)據(jù)反饋給瀏覽器之前,事務(wù)處理的數(shù)據(jù)必須保持正確。
決策3:訪問(wèn)數(shù)據(jù)庫(kù)
無(wú)論你怎樣對(duì)業(yè)務(wù)邏輯怎樣的組織和封裝,最終你還是要從數(shù)據(jù)庫(kù)中取數(shù)據(jù)出來(lái)。在經(jīng)典的J2EE應(yīng)用程序中,你有2個(gè)選擇:JDBC——這個(gè)需要很多的底層代碼;或者實(shí)體Bean——這個(gè)用起來(lái)非常困難,而且缺少重要特征。相比來(lái)說(shuō),使用輕量級(jí)構(gòu)架令人高興的事情之一就是:你有一些新的而且更有力的方法去訪問(wèn)數(shù)據(jù)庫(kù),而且這種方法可以顯著的減少訪問(wèn)數(shù)據(jù)庫(kù)的代碼。讓咱們來(lái)進(jìn)一步研究。
直接用JDBC會(huì)有什么問(wèn)題
最近突然出現(xiàn)了對(duì)象/關(guān)系 映射構(gòu)架(比如JDO和Hibernate) 和SQL映射構(gòu)架(比如iBATIS)這些不是憑空出現(xiàn)的。相反,他們是在JAVA 聯(lián)盟在JDBC屢造挫折之后才出現(xiàn)的。為了了解新構(gòu)架出現(xiàn)的原因,這里咱們回顧一下直接使用JDBC會(huì)出現(xiàn)的問(wèn)題。在許多程序中直接使用JDBC不是一個(gè)好的選擇,主要有以下三個(gè)原因:。 開(kāi)發(fā)和維護(hù)SQL非常的困難而且耗費(fèi)時(shí)間——一些開(kāi)發(fā)者發(fā)現(xiàn)要寫(xiě)龐大而且復(fù)雜的SQL語(yǔ)句非常的困難。反映數(shù)據(jù)庫(kù)變化的SQL語(yǔ)句會(huì)變得非常耗時(shí)。你必須小心的考慮犧牲可維護(hù)性是否值得。。 用SQL會(huì)使移植性變的很差——因?yàn)樾枰獢?shù)據(jù)庫(kù)的特殊SQL語(yǔ)句。如果一個(gè)程序和多個(gè)數(shù)據(jù)庫(kù)有關(guān)系,那么你就要寫(xiě)多個(gè)版本的SQL語(yǔ)句,這使得可維護(hù)性變變成噩夢(mèng)。。 直接寫(xiě)JDBC代碼要會(huì)非常耗時(shí),而且容易出錯(cuò)。你必須寫(xiě)很多的樣板代碼去獲得連接,創(chuàng)建和初始化適當(dāng)?shù)穆暶鳎€要用精確的聲明去清理連接。而且你還要寫(xiě)代碼去將JAVA 對(duì)象映射到SQL聲明。由于要無(wú)奈的去寫(xiě),JDBC代碼很容易出錯(cuò)。
如果你的程序必須直接運(yùn)行SQL語(yǔ)句的話,那前面兩個(gè)問(wèn)題是無(wú)法避免的。有時(shí)候?yàn)榱双@得好的性能,必須要全力的寫(xiě)SQL語(yǔ)句,包括供應(yīng)商提供的那些特殊東西。由于許多業(yè)務(wù)上的原因,持久層可能會(huì)產(chǎn)生混亂的SQL語(yǔ)句,為了防止這種情況,DBA可能要求你的程序來(lái)完全控制SQL語(yǔ)句的執(zhí)行。通常,團(tuán)隊(duì)買進(jìn)的關(guān)系型數(shù)據(jù)庫(kù)過(guò)于龐大,以至于應(yīng)用程序工作時(shí)會(huì)出現(xiàn)一些和數(shù)據(jù)庫(kù)有關(guān)的瑣碎事務(wù)。根據(jù)“iBATIS in Action”的作者說(shuō)這里會(huì)有一種情況出現(xiàn):“數(shù)據(jù)庫(kù)或者SQL語(yǔ)句本身存在的時(shí)間比程序代碼存在的時(shí)間還要長(zhǎng),或者同一段SQL語(yǔ)句或數(shù)據(jù)庫(kù)有多個(gè)程序的版本。有些情況下,程序已經(jīng)用另外一種語(yǔ)言重寫(xiě)了,但是SQL語(yǔ)句和數(shù)據(jù)庫(kù)卻沒(méi)有太大的改變?!?如果直接使用SQL弄的你筋疲力盡,那么很幸運(yùn),這里有一種直接執(zhí)行SQL語(yǔ)句的構(gòu)架,它可比用JDBC要容易多了。當(dāng)然了,這就是iBATIS.
使用iBATIS
我開(kāi)發(fā)過(guò)的所有企業(yè)JAVA應(yīng)用程序,都是直接執(zhí)行SQL語(yǔ)句的。早期的程序是執(zhí)行特定的SQL語(yǔ)句的,后來(lái)是用持久層構(gòu)架再用少量的SQL語(yǔ)句構(gòu)成的。一開(kāi)始我直接用JDBC來(lái)執(zhí)行SQL語(yǔ)句,但是后來(lái),我經(jīng)常寫(xiě)一些小的構(gòu)架去完成JDBC中那些比較無(wú)聊的部分。我也用過(guò)一段Spring的JDBC類,這些類除去了JDBC中的許多樣板代碼。但是無(wú)論是我自己寫(xiě)的構(gòu)架還是使用Spring的類,在Java類映射到SQL語(yǔ)句的時(shí)候都會(huì)存在問(wèn)題,這就是我為什么那么高興的加入iTATIS 那邊的原因了。
iBATIS 不僅將應(yīng)用程序完全的與“數(shù)據(jù)庫(kù)連接”、具體的SQL語(yǔ)句隔絕開(kāi)來(lái),更實(shí)現(xiàn)了通過(guò)XML描述文檔來(lái)將JavaBean 映射到SQL語(yǔ)句。它用Java bean 內(nèi)省機(jī)制來(lái)將“道具bean(bean properties)”映射為相應(yīng)的數(shù)據(jù)庫(kù)語(yǔ)句占位符,而且它可以將ResultSet后的結(jié)果構(gòu)造為bean.它還可以通過(guò)數(shù)據(jù)庫(kù)生成主鍵,自動(dòng)加載相關(guān)的對(duì)象、實(shí)現(xiàn)緩存和lazy loading.這樣,iBATIS 就除去了許多執(zhí)行SQL語(yǔ)句帶來(lái)的苦差。通過(guò)編輯XML描述文檔和調(diào)用少量的iBATIS的API,代替了寫(xiě)大量的JDBC底層代碼。