http://dev2dev.bea.com.cn/blog/chaocai/200712/spring_osgi_04_719.html
http://dev2dev.bea.com.cn/bbs/ext/dev2devperson/
蔡超
http://dev2dev.bea.com.cn/blog/chaocai/200710/architecture_24_536.html
多層結(jié)構(gòu)是J2EE應(yīng)用開發(fā)的基本模式,很多開發(fā)者都會(huì)按照多層結(jié)構(gòu)來組織自己的應(yīng)用(通常分為Facade,Application Service,DAO等層),但是他們往往會(huì)選擇在不同層上去控制事務(wù)和Hibernate Session的邊界,可千萬不要小看這樣的選擇它會(huì)大大影響程序的可維護(hù)性和可復(fù)用性。
其實(shí)在Facade層來控制事務(wù)的邊界通常都是最佳選擇。我們知道Facade層的粗粒度接口是直接為用戶請(qǐng)求提供相應(yīng)服務(wù)的,在典型的J2EE環(huán)境中通常使用Session Bean來實(shí)現(xiàn)Facade層,并且使用CMT。這時(shí)如果有的開發(fā)人員在其他層次控制了事務(wù)如DAO,由于這些層次通常不會(huì)采用EJB實(shí)現(xiàn),所以所使用的事務(wù)為容器提供的用戶管理事務(wù),根據(jù)EJB的事務(wù)規(guī)范CMT是無法把事務(wù)上下文傳遞到用戶管理事務(wù)的邊界中的,由于J2EE并不支持事務(wù)的嵌套,所以當(dāng)來自Facade的CMT事務(wù)遇見DAO的事務(wù)時(shí),內(nèi)部事務(wù)將被掛起,這樣整個(gè)事務(wù)的情況,就會(huì)和設(shè)想的業(yè)務(wù)邏輯產(chǎn)生很大的差異。
并且有時(shí)不同業(yè)務(wù)邏輯的實(shí)現(xiàn)會(huì)復(fù)用DAO提供多個(gè)方法,所以很難控制事務(wù)的邊界,導(dǎo)致這些方法難以被復(fù)用。
對(duì)于Hibernate Session,由于存在懶加載的問題,所以開發(fā)人員常會(huì)預(yù)見這樣的異常LazyInitializationException。避免這個(gè)問題就要求在關(guān)閉session前要裝載好要使用的對(duì)象關(guān)系域。而這種邏輯通常只與界面顯示內(nèi)容相關(guān),如果把session的邊界控制放置在DAO或者Application Service中就會(huì)使業(yè)務(wù)邏輯的實(shí)現(xiàn)要和界面顯示邏輯混合在一起,我們必須在這些方法中加載那些界面顯示需要的對(duì)象關(guān)系域。而界面顯示是經(jīng)常變化的,并且業(yè)務(wù)邏輯會(huì)被多個(gè)不同的界面所復(fù)用,如果這樣Application Service,DAO中方法的復(fù)用性就會(huì)大大降低。
把這些工作放在離表現(xiàn)層最近的Facade中便可以避免這些問題。
注意在其他層次中我們不需要控制session的邊界,我們通常采用getCurrentSession()來獲得當(dāng)前事務(wù)中的session,記住這個(gè)方法必須在事務(wù)上下文存在的情況下才可以調(diào)用,并且在事務(wù)被提交的時(shí)候Hibernate會(huì)在自動(dòng)關(guān)閉session,所以我們不要顯示的關(guān)閉session.
你是否已經(jīng)被像JBPM,XFLow等那樣的復(fù)雜編程和配置搞頭昏腦脹;被他們所依賴的大量jar和容器搞得不知所措。
如果這樣就試試筆者開發(fā)的這個(gè)簡(jiǎn)單工作流引擎吧,配置和編程都很簡(jiǎn)單,也不依賴任何容器。支持spring的版本。
下載地址:
http://m.tkk7.com/Files/chaocai/swf-beta-1[1].3-bin.zip
內(nèi)附用戶手冊(cè)
(SWF開發(fā)設(shè)計(jì):蔡超,北京天融信,
chaocai2001@yahoo.com.cn)
簡(jiǎn)介
SWF是一種嵌入式的工作流引擎,它不需要任何應(yīng)用服務(wù)器的支持。SWF使用十分簡(jiǎn)單,但卻可以滿足多數(shù)流程驅(qū)動(dòng)應(yīng)用的需求。并且支持和主流j2ee框架整合(spring).
本文介紹如何基于SWF開發(fā)流程驅(qū)動(dòng)的應(yīng)用。
你是否已經(jīng)被像JBPM,XFLow等那樣的復(fù)雜編程和配置搞頭昏腦脹;被他們所依賴的大量jar和容器搞得不知所措。
如果這樣就試試筆者開發(fā)的這個(gè)簡(jiǎn)單工作流引擎吧,配置和編程都很簡(jiǎn)單,也不依賴任何容器。馬上會(huì)推出支持spring的版本。
下載地址:
http://m.tkk7.com/Files/chaocai/swf-beta-1-bin.zip
內(nèi)附用戶手冊(cè)
(SWF開發(fā)設(shè)計(jì):蔡超,北京天融信,
chaocai2001@yahoo.com.cn)
簡(jiǎn)介
SWF是一種嵌入式的工作流引擎,它不需要任何應(yīng)用服務(wù)器的支持。SWF使用十分簡(jiǎn)單,但卻可以滿足多數(shù)流程驅(qū)動(dòng)應(yīng)用的需求。
本文介紹如何基于SWF開發(fā)流程驅(qū)動(dòng)的應(yīng)用。
問題
隨著輕量級(jí)持久化框架的流行(如:Hibernate,JDO,JPA),領(lǐng)域?qū)ο笕〈藗鹘y(tǒng)的DTO直接作為值對(duì)象,而在這種架構(gòu)應(yīng)用的開發(fā)過程中,開發(fā)人員常會(huì)預(yù)見這樣的異常LazyInitializationException。上述問題是由于Hibernate對(duì)于領(lǐng)域?qū)ο蟮年P(guān)系域?qū)ο蟛扇×藨屑虞d策略所導(dǎo)致的(即在關(guān)系域被訪問時(shí)才真正加載創(chuàng)建這些相關(guān)對(duì)象,Hibernate提供的懶加載策略在很多時(shí)候都可以讓我的程序獲得更高的效率);由于領(lǐng)域?qū)ο笤诿摴艿臓顟B(tài)下被作為值對(duì)象傳回顯示層,而顯示層如果訪問了采用懶加載策略加載的關(guān)系域,便會(huì)導(dǎo)致LazyInitializationException異常。
為了避免這個(gè)問題,我們常常會(huì)在Façade層的業(yè)務(wù)方法中加入與特定顯示要求相綁定的返回對(duì)象初始化過程(即裝載那些被懶加載了的關(guān)系域?qū)ο螅?/span>Façade通常是我們用于控制事務(wù)邊界和完成返回的領(lǐng)域?qū)ο竺撱^的地方。
1 表現(xiàn)層是易變的這樣就會(huì)導(dǎo)致連鎖反應(yīng),大量的代碼需要維護(hù),完全違背了面向?qū)ο笤O(shè)計(jì)的原則,增加了程序的維護(hù)成本。
2 并且Façade可能用于支持多種不同的表現(xiàn)層,很難讓一個(gè)方法滿足不同的要求。
OSIV(Open Session in View)結(jié)構(gòu)是一種解決上述問題的方法,這種結(jié)構(gòu)之所以能解決上述問題關(guān)鍵就在于OSIV在表現(xiàn)層中控制Session的打開和關(guān)閉,控制事務(wù)邊界。OSIV雖然簡(jiǎn)化了應(yīng)用程序的結(jié)構(gòu),也避免了LazyInitializationException問題,但是也有很多不足:1.增加了表示層的負(fù)責(zé)度,2.在響應(yīng)返回表示層前必須提交事務(wù)。3.由于減少了封裝層次,表現(xiàn)層直接操作領(lǐng)域?qū)ο笫沟冒ㄐ阅芊矫娴母鞣N優(yōu)化更為困難。
解決方案
思考既然表示層知道要顯示的信息,即領(lǐng)域?qū)ο髴?yīng)該加載哪些相關(guān)聯(lián)的對(duì)象。那么我們何不把這個(gè)任務(wù)交給Façade的調(diào)用者(表現(xiàn)層)來完成呢?
不同的表示層可能會(huì)有不同的顯示策略,利用策略模式(GoF)我們讓表示層來注入所需的關(guān)系域加載策略實(shí)現(xiàn)。
下面便是這個(gè)想法的實(shí)現(xiàn):
示例中的領(lǐng)域模型:

圖表 1示例中領(lǐng)域?qū)ο竽P?/span>
示例中相關(guān)的組件

圖表 2示例相關(guān)組件
LazyObjectLoader:懶對(duì)象加載者接口,其定義如下
來對(duì)象加載策略接口
package org.ccsoft;
publicinterface LazyObjectLoader {
publicvoid loadLazyObjects(Object obj);
}
該接口定義了不同懶對(duì)象加載策略實(shí)現(xiàn)者要實(shí)現(xiàn)的方法,在loadLazyObjects方法中實(shí)現(xiàn)對(duì)領(lǐng)域?qū)ο?/span>obj相關(guān)的關(guān)系域?qū)ο筮M(jìn)行加載的策略。
OrderItemLoader一種加載策略的實(shí)現(xiàn),用于加載Order對(duì)象的關(guān)系域?qū)ο?/span>OrderItem對(duì)象
package org.ccsoft;
import java.io.Serializable;
publicclass OrderItem implements Serializable {
private String detail;
public String getDetail() {
returndetail;
}
publicvoid setDetail(String detail) {
this.detail = detail;
}
}
OrderMgrFacadeImp: Façade的實(shí)現(xiàn),可以使POJO也可以使Session Bean
package org.ccsoft;
publicclass OrderMgrFacadeImp implements OrderMgrFacade {
private OrderDAO orderDAO;
public OrderDAO getOrderDAO() {
returnorderDAO;
}
publicvoid setOrderDAO(OrderDAO orderDAO) {
this.orderDAO = orderDAO;
}
public Order getOrder(int orderId, LazyObjectLoader loader) {
Order order=orderDAO.getOrder(orderId);
loader.loadLazyObjects(order);
return order;
}
}
在getOrder方法中我們要求調(diào)用者提供了懶對(duì)象裝載策略的實(shí)例用于裝載那些調(diào)用者要用到的關(guān)系域?qū)ο蟆W⒁庠撌纠峭ㄟ^spring實(shí)現(xiàn)的,利用spring AOP完成事務(wù)管理,事務(wù)的邊界在Façade中方法上,當(dāng)方法執(zhí)行結(jié)束,事務(wù)業(yè)務(wù)將結(jié)束,并且Hibernate會(huì)自動(dòng)關(guān)閉session,我們看到getOrder方法中在事務(wù)結(jié)束前調(diào)用了懶對(duì)象裝載策略,從而按照調(diào)用者的要求裝載了調(diào)用者所需的關(guān)系域?qū)ο蟆?/span>
該模式的優(yōu)點(diǎn)
1 將領(lǐng)域?qū)ο蟮奶幚磉壿嬇c顯示層的顯示邏輯完全分離,提高了代碼的可維護(hù)性和可擴(kuò)展性
該模式的不足
1 要求顯示層的開發(fā)者,了解懶加載的情況
2 增加了代碼的復(fù)雜性
________________________________________________________________________
蔡 超
SCEA , SCBCD , MCSD
IBM Certified Specialist RUP
IBM Certified Solution Designer OOA&D UML v2
北京天融信軟件架構(gòu)師
SUN,Microsoft培訓(xùn)中心特邀高端教師
常年提供架構(gòu)咨詢服務(wù)
chaocai2001@yahoo.com.cn , 010-82776427