J2EE 是Java技術(shù)在企業(yè)運(yùn)算上的應(yīng)用,它包含多種運(yùn)算標(biāo)準(zhǔn),如EJB組件架構(gòu)、JDBC數(shù)據(jù)庫(kù)運(yùn)算、JMS信息傳遞、Java Servlets/JSP等Web組件程序等,功能強(qiáng)大且內(nèi)容博大精深。為了讓使用者可以有一個(gè)設(shè)計(jì)J2EE架構(gòu)應(yīng)用程序的模板,Sun做出一套系統(tǒng)名為“Java寵物商店(Pet Store)”。這個(gè)網(wǎng)上寵物店的范例是針對(duì)已經(jīng)熟悉Java程序設(shè)計(jì)和J2EE概念人員的。這個(gè)系統(tǒng)是使用正規(guī)方式設(shè)計(jì)出來(lái)的,使得使用J2EE架構(gòu)的人員有了一個(gè)參考的依據(jù)。這個(gè)范例一出來(lái),很快就被用來(lái)當(dāng)成比較各家J2EE兼容產(chǎn)品的依據(jù)。Oracle的J2EE Application Server(Oracle 9iAS)、BEA WebLogic Server、IBM WebSphere都有相應(yīng)的產(chǎn)品。Java標(biāo)準(zhǔn)的精神原本就是各家廠商合作制定技術(shù)標(biāo)準(zhǔn),然后再根據(jù)這個(gè)標(biāo)準(zhǔn)來(lái)評(píng)選出最優(yōu)產(chǎn)品。
Java Pet Store使用的架構(gòu)設(shè)計(jì)就是所謂的MVC 設(shè)計(jì)模式。MVC是Model-View-Controller的簡(jiǎn)寫,是設(shè)計(jì)模式的一種,源自Smalltalk。MVC模式則是將對(duì)象分成三類,Model對(duì)象專門用來(lái)包裝應(yīng)用程序的狀態(tài),View用來(lái)負(fù)責(zé)屏幕上的展現(xiàn),Controller則負(fù)責(zé)定義應(yīng)用程序的各種動(dòng)作和反應(yīng)。Java寵物店系統(tǒng)利用MVC模式設(shè)計(jì)整個(gè)系統(tǒng)架構(gòu),將各層的對(duì)象清楚地分開。Java寵物店的目的是展示一個(gè)具有擴(kuò)充性的企業(yè)運(yùn)算架構(gòu),就是采用三層(3-Tiers)式設(shè)計(jì):資料展現(xiàn)層在最外面,中間是執(zhí)行企業(yè)運(yùn)算邏輯的中間層組件,后端就是單純存放資料的關(guān)系型數(shù)據(jù)庫(kù)。Java寵物店當(dāng)初的用意也只是當(dāng)成一個(gè)J2EE架構(gòu)設(shè)計(jì)的模板,并沒有特別針對(duì)加速執(zhí)行效能作額外的設(shè)計(jì)。
系統(tǒng)構(gòu)架與寵物商店簡(jiǎn)介
系統(tǒng)構(gòu)架
Pet Store網(wǎng)站系統(tǒng)采用松耦合的設(shè)計(jì)架構(gòu),可以和多個(gè)數(shù)據(jù)源、EIS進(jìn)行交互。這個(gè)例子共分成4個(gè)部分:
1.Web購(gòu)物站點(diǎn);
2.管理部分,包括銷售統(tǒng)計(jì)、手工接受/拒絕訂單;
3.訂單處理,包括以下4部分內(nèi)容:
◆ 通過JMS接受/處理訂單消息;
◆ 用Java Mail來(lái)通知客戶;
◆ 通過JMS發(fā)訂單給供應(yīng)商;
◆ 維護(hù)訂單數(shù)據(jù)庫(kù)。
4.供應(yīng)商,此部分包括以下內(nèi)容:
◆ 通過JMS接受訂單;
◆ 派送貨物給用戶;
◆ 提供一個(gè)基于Web的庫(kù)存管理;
◆ 維護(hù)庫(kù)存數(shù)據(jù)庫(kù)。
寵物店網(wǎng)上商店功能
通過瀏覽器可以訪問此商店。客戶通過瀏覽,可以把貨物放入購(gòu)物車,創(chuàng)建賬戶/登錄賬戶,創(chuàng)建訂單,然后通過信用卡支付。
寵物商店結(jié)構(gòu)
寵物店的網(wǎng)站服務(wù)是從上而下的。最上層是WAF(Web Application Framework)來(lái)控制應(yīng)用的屏幕跳轉(zhuǎn),產(chǎn)生視圖,然后調(diào)用商業(yè)組件來(lái)完成商業(yè)處理(如圖1所示)。

圖1 Java Pet Store 結(jié)構(gòu)
WAF提供了許多Web應(yīng)用所需的服務(wù),包括請(qǐng)求的過濾和分發(fā)、模板視圖的產(chǎn)生、一系列可重用的Taglib,以及屏幕流程控制等。應(yīng)用組件封裝了處理的邏輯,它們代表了商業(yè)的數(shù)據(jù),并且操作這些商業(yè)數(shù)據(jù),實(shí)體EJB代表了商業(yè)實(shí)體,如客戶、地址、賬目。會(huì)話EJB提供了一些方法,如登陸一個(gè)用戶、輸出一個(gè)用戶、管理購(gòu)物車等。其它會(huì)話EJB提供了一些共同的方法,如產(chǎn)生唯一標(biāo)示符。傳統(tǒng)的JavaBean組件變成了值對(duì)象,用來(lái)在EJB組件和應(yīng)用間傳遞數(shù)據(jù)。XML文檔類則用來(lái)處理訂單信息。
這個(gè)寵物店例子的WAF是對(duì)J2EE藍(lán)圖Web層規(guī)范的實(shí)現(xiàn)。一個(gè)Web層處理一般可以劃分成四步(如圖2所示):
◆ 解釋一個(gè)請(qǐng)求;
◆ 執(zhí)行一個(gè)商業(yè)邏輯處理;
◆ 選擇下一個(gè)視圖;
◆ 產(chǎn)生這個(gè)視圖。

圖2 WAF的Web層處理
寵物店模塊設(shè)計(jì)
寵物店由一些獨(dú)立模塊組成:
◆ 控制模塊 它來(lái)分發(fā)請(qǐng)求到各個(gè)業(yè)務(wù)處理邏輯、控制屏幕跳轉(zhuǎn)、處理對(duì)應(yīng)的組件及用戶;
◆ 登錄和注冊(cè) 控制模塊由WAF實(shí)現(xiàn)和擴(kuò)展;
◆ 購(gòu)物車模塊 購(gòu)物車跟蹤用戶購(gòu)物過程;
◆ 登錄模塊 需要用戶登錄在某些頁(yè)面登錄;
◆ 消息模塊 從寵物店到等單中心用來(lái)異步傳輸訂單;
◆ 類別模塊 根據(jù)用戶查詢需求提供一個(gè)類別視圖;
◆ 客戶模塊 表示客戶信息,如地址、信用卡、聯(lián)系方式等(如圖3所示)。

圖3 Java pet Store 模塊設(shè)計(jì)
在圖3中,控制模塊控制所有的交互和執(zhí)行,每個(gè)用戶會(huì)話都有一個(gè)購(gòu)物車對(duì)應(yīng)。
寵物店的組件
1. EJB,代表了商業(yè)數(shù)據(jù)和執(zhí)行商業(yè)邏輯處理;
2. JSP頁(yè)面, 定義了整個(gè)應(yīng)用的視圖框架模板(template.jsp)和模板組成的各個(gè)JSP文件,以及各種被引用的圖形文件;
3. XML文件,用來(lái)定義屏幕、屏幕跳轉(zhuǎn)控制、綁定URL到某個(gè)HTML Action、定制signOn以及J2EE部署的部署XML文件;
4. Servlet過慮器, 用來(lái)校驗(yàn)用戶安全的登陸和輸出的編碼;
5. 異步信息發(fā)送組件,傳輸使用XML封裝的訂單到訂單處理中心;
6. 一個(gè)安裝程序,用來(lái)產(chǎn)生例子數(shù)據(jù)庫(kù)。
分析寵物商店的應(yīng)用
下面就按照MVC架構(gòu)和層次化應(yīng)用模型來(lái)分析這個(gè)應(yīng)用。
模型—視圖—控制架構(gòu)
1.應(yīng)用模型劃分方法
分析一個(gè)實(shí)際應(yīng)用可以有三種劃分的方法:第一種劃分方法為模型—視圖—控制(MVC)架構(gòu)。這種方法把應(yīng)用分解成數(shù)據(jù)、顯示和控制三個(gè)部分。第二種劃分方法把應(yīng)用按照不同的角色劃分成不同的層次,分離客戶端、Web層、EJBs層和底端的數(shù)據(jù)層或遺留系統(tǒng)層,即J2EE應(yīng)用的層次劃分方法。第三種劃分是傳統(tǒng)的功能模塊劃分。
劃分的目的是使復(fù)雜的問題清晰化、條理化。每一種劃分雖然增加了額外的復(fù)雜性,但也有它的好處。MVC架構(gòu)為應(yīng)用組件提供一個(gè)靈活的、可重用的、易測(cè)試的、可擴(kuò)展的和清晰的設(shè)計(jì)角色。多層設(shè)計(jì)使實(shí)現(xiàn)技術(shù)的選擇靈活,同時(shí)具有可升級(jí)和可擴(kuò)展性。模塊化的設(shè)計(jì)把系統(tǒng)分解成小的直接模塊,可以進(jìn)行單獨(dú)分析、測(cè)試和理解。
現(xiàn)在企業(yè)級(jí)應(yīng)用與以前相比,要更多地支持使用不同類型接口的多類型用戶,例如在線商店需要為Web顧客提供HMTL主頁(yè)、為無(wú)線顧客提供XML主頁(yè)、為系統(tǒng)管理員提供JFC/Swing接口、為供應(yīng)商提供基于XML的Web服務(wù)等(見圖4)。

圖4 Java Pet Store 支持的各種類型用戶關(guān)系圖
當(dāng)開發(fā)一個(gè)支持單一類型客戶端的應(yīng)用時(shí),可以把數(shù)據(jù)訪問邏輯、顯示控制邏輯和接口邏輯交織在一起。但對(duì)于支持多類型客戶端的企業(yè)系統(tǒng)來(lái)說,這是很麻煩的。因此:
◆ 對(duì)于每種類型的客戶端接口,需開發(fā)不同的應(yīng)用;
◆ 每個(gè)應(yīng)用的非界面代碼是重復(fù)的,在實(shí)現(xiàn)、測(cè)試和維護(hù)方面需重復(fù)工作;
◆ 復(fù)制工作本身是昂貴的,因?yàn)榻缑媾c非界面代碼交織;
◆ 重復(fù)工作不可避免,而且是有缺陷而緩慢的。
2.使用模型—視圖—控制架構(gòu)
通過在J2EE應(yīng)用中使用模型—視圖—控制架構(gòu),把核心數(shù)據(jù)和數(shù)據(jù)訪問功能與使用這些功能的顯示控制邏輯分開,如圖5所示。這種分離允許多視圖共享同樣的企業(yè)數(shù)據(jù)模型。

圖5 MVC架構(gòu)
MVC架構(gòu)起源于Smalltalk,最初用來(lái)在傳統(tǒng)的圖形用戶界面模型中映射輸入、處理和輸出任務(wù)。然而,它可以直接用來(lái)映射多層企業(yè)應(yīng)用中的相關(guān)概念,具體概念介紹如下:
模型(Model)代表企業(yè)數(shù)據(jù)和業(yè)務(wù)規(guī)則,用來(lái)控制訪問和數(shù)據(jù)更新。模型是接近現(xiàn)實(shí)世界的服務(wù)軟件,因此現(xiàn)實(shí)世界的建模技術(shù)可以應(yīng)用模型。
視圖(View)代表模型的內(nèi)容。它通過模型訪問企業(yè)數(shù)據(jù)并指定這些數(shù)據(jù)的顯示。視圖負(fù)責(zé)模型狀態(tài)改變后呈現(xiàn)給用戶的數(shù)據(jù)也相應(yīng)改變。可以通過推(Push)模型實(shí)現(xiàn),即視圖在模型中注冊(cè)獲取更新指令,或者拉(Pull)模型,即由視圖負(fù)責(zé)在需要獲取最新數(shù)據(jù)的時(shí)候調(diào)用模型。
控制(Controller)把與視圖交互轉(zhuǎn)化成模型執(zhí)行的動(dòng)作。在獨(dú)立運(yùn)行的GUI客戶端,用戶交互可能是按鈕或菜單,而在Web應(yīng)用中是GET和POST HTTP請(qǐng)求。模型執(zhí)行的動(dòng)作包括激活業(yè)務(wù)處理進(jìn)程或改變模型狀態(tài)。以用戶交互和模型動(dòng)作結(jié)果為基礎(chǔ),控制通過選擇合適的視圖完成相應(yīng)功能。
MVC架構(gòu)有如下優(yōu)點(diǎn):
◆ 多視圖使用同一模型。模型與視圖分離允許多視圖使用同一企業(yè)模型。因此,企業(yè)級(jí)應(yīng)用模型組件容易實(shí)現(xiàn)、測(cè)試和維護(hù)。
◆ 容易支持新類型的客戶端。支持一個(gè)新類型的客戶端,只需寫一個(gè)視圖和控制,然后把它連到現(xiàn)存的企業(yè)模型中。
分析Java Pet Store應(yīng)用
視圖
視圖是用戶界面和應(yīng)用程序的接口。在Java Pet Store中,視圖在Web層實(shí)現(xiàn)。共有三種組件實(shí)現(xiàn)視圖:JSP頁(yè)面、JSP自定義標(biāo)記和JavaBean。視圖部分涉及到三方面內(nèi)容:
1.屏幕
屏幕是一個(gè)頁(yè)面顯示的所有內(nèi)容。根據(jù)需要,在ScreenDefinitions.jsp中定義如下屏幕:
Name:MAIN_SCREEN,DEFAULT_SCREEN
Name:CATEGORY_SCREEN
Name:SEARCH_SCREEN
Name:PRODUCT_SCREEN
Name:PRODUCT_DETAILS_SCREEN
Name:CART_SCREEN
Name:CHECKOUT_SCREEN
Name:PLACEORDER_SCREEN
Name:COMMIT_ORDER_SCREEN
Name:SIGNIN_SCREEN
Name:SIGNUP_SCREEN
|
2.模板
因?yàn)橐拐麄€(gè)網(wǎng)站的頁(yè)面具有相同的特征,如每個(gè)頁(yè)面都要有Logo、Banner等相同的元素,所以采用模板定義頁(yè)面的不同組成部分。本示例中定義的模板元素有footer.jsp、banner.jsp和index.jsp等。ScreenDefinitions.jsp定義好的屏幕包括這些模板元素,通過include指令包含到頁(yè)面中
3.視圖選擇
視圖的選擇是通過控制來(lái)完成的。控制根據(jù)實(shí)際情況分析用戶顯示視圖的ID,運(yùn)行模板把整個(gè)視圖顯示出來(lái),如圖6所示。

圖6 視圖選擇
模型
模型的狀態(tài)是視圖顯示的數(shù)據(jù)來(lái)源,也是控制的具體對(duì)象。在J2EE中,描述模型的狀態(tài)采用三種EJB:無(wú)狀態(tài)會(huì)話EJB、有狀態(tài)會(huì)話EJB和實(shí)體EJB。
1.輔助對(duì)象
有兩種主要的輔助對(duì)象:數(shù)據(jù)庫(kù)訪問對(duì)象和值對(duì)象。對(duì)于實(shí)體EJB來(lái)說,數(shù)據(jù)庫(kù)訪問對(duì)象封裝了數(shù)據(jù)庫(kù)訪問的方法,如AccountDAO等。對(duì)于所有EJB的屬性值,則都由一個(gè)值對(duì)象來(lái)封裝,如ShoppingCartModel、AccountModel等。
2.EJBs
本示例用到的EJBs如圖7所示。

圖7 Java Pet Store使用到的EJBs
3.模型狀態(tài)到視圖的綁定
一個(gè)模型對(duì)應(yīng)多個(gè)視圖,實(shí)現(xiàn)視圖的綁定方法是:ModelUpdateListener和ModelUpdateNotifier實(shí)現(xiàn)了一種注冊(cè)-監(jiān)聽模式,通過調(diào)用監(jiān)聽器的performUpdate方法來(lái)使視圖得到更新。例如:
public class AccountWebImpl extends AccountModel
implements ModelUpdateListener{
private ModelManager mm;
private Account acctEjb;
public AccountWebImpl(ModelManager mm){
super(null,null,null};
this.mm=mm;
mm.addListener(JNDINames.ACCOUNT_EJBHOME,this);
}
public void performUpdate(){
if(acctEjb==null) {
acctEjb=mm.getAccountEJB();
}
try{
if(acctEjb !=null)copy(acctEjb.getDetails());
}catch(RemoteException re){
throw new GeneralFailureException(re);
}
}
}
|
控制
控制負(fù)責(zé)處理用戶請(qǐng)求、調(diào)用相應(yīng)的模型、更新模型的狀態(tài)、刷新視圖以及返回用戶合理的頁(yè)面。示例的所有控制對(duì)象如圖8所示。

圖8 控制對(duì)象圖
1.RequestProcessor
RequestProcessor接收并處理用戶的所有請(qǐng)求,調(diào)用RequestToEventTranslator對(duì)象把請(qǐng)求轉(zhuǎn)換成預(yù)定義的事件,在事件處理完成后,進(jìn)行視圖更新。 代碼如下所示:
public class RequestProcessor{
private ShoppingClientControllerWebImpl scc;
private ModelManager mm;
private ModelUpdateNotifier mun;
private RequestToEventTranslator eventTranslator;
private SecurityAdapter securityAdapter;
public void init(...) {
mm = (ModelManager)session.getAttribute("modelManager");
mun = mm;
SCC = new ShoppingClientControllerWebImpl(session);
eventTranslator= new RequestToEventTranslator(this,mm);
}
public void processRequest(HttpServletRequest req){
checkForWebServerLogin(req);
EStoreEvent event = eventTranslator.processRequest(req);
if (event != null){
Collection updatedModelList = scc.handleEvent(event);
mun.notifyListeners(updatedModelList);
}
}
}
|
2.ShoppingClientControllerWebImpl
ShoppingClientContronerWebImpl是調(diào)用EJB層的ShoppingClientController代理對(duì)象,代碼如下所示:
public class ShoppingClientControllerWebImpl{
private com....ejb.ShoppingClientController sccEjb;
private HttpSession session;
public ShoppingClientControllerWebImpl(HttpSession session){
this.session = session;
ModelManager mm= (ModelManager)session.getAttribute("modelManager");
sccEjb = mm.getSCCEJB();
}
public synchronized AccountModel getAccount(){
return sccEjb.getAccount().getDetails();
}
......
public synchronized Collection handleEvent(EStoreEvent ese){
return sccEjb.handleEvent(ese);
}
public synchronized void remove() {
sccEjb.remove();
}
}
|
3.ShoppingClientController
ShoppingClientController是有狀態(tài)的會(huì)話EJB,它為每個(gè)用戶建立一個(gè)單獨(dú)的實(shí)例,負(fù)責(zé)購(gòu)物車和賬號(hào)的生命周期,并負(fù)責(zé)處理事件。同時(shí)它也控制狀態(tài)機(jī)StateMachine的生命周期。代碼參見賽迪網(wǎng)http://linux.ccidnet.com的期刊瀏覽2003年第6期。
4.StateMachine
StateMachine實(shí)現(xiàn)核心的業(yè)務(wù)邏輯,它負(fù)責(zé)改變模型的狀態(tài),包括處理每個(gè)業(yè)務(wù)事件的方法。代碼參見賽迪網(wǎng)http://linux.ccidnet.com的期刊瀏覽2003年第6期。
小結(jié)
J2EE網(wǎng)站的開發(fā)方法,即是Internet的開發(fā)方法。Internet開發(fā)的發(fā)展可以劃分為三個(gè)階段:第一階段是將業(yè)務(wù)邏輯和表現(xiàn)邏輯完全集成在一起,采用HTML、JSP和Servlets技術(shù)開發(fā);第二階段是將業(yè)務(wù)邏輯和表現(xiàn)邏輯分開,采用HTML、JSP、Servlets、JavaBeans Compoments和Custom Tags技術(shù)開發(fā);第三個(gè)階段是MVC設(shè)計(jì)模式(J2EE的開發(fā)方法)。今天,MVC設(shè)計(jì)模式已成為Internet開發(fā)發(fā)展的主流。無(wú)論是通過第一階段開發(fā)的應(yīng)用,還是通過第二階段開發(fā)的應(yīng)用,都會(huì)面臨著開發(fā)人員的分工、應(yīng)用的可維護(hù)性和可擴(kuò)展性及可測(cè)量性的問題。為此,我們?cè)谠O(shè)計(jì)階段關(guān)心的重點(diǎn)是系統(tǒng)結(jié)構(gòu)的復(fù)雜程度、代碼之間的耦合度、代碼的易維護(hù)性、應(yīng)用框架的可重用性、EJB組件的可重用性和易測(cè)試性,以及不同技能開發(fā)人員的分工等。用縱觀全局的眼光來(lái)看,在Internet系統(tǒng)開始設(shè)計(jì)的時(shí)候,就要考慮開發(fā)、運(yùn)行、維護(hù)階段的問題
|