Java EE核心模式學(xué)習(xí)理解和記錄

導(dǎo)讀:從JDK 5.0開(kāi)始 J2EE 改名為 Java EE。 Java EE被企業(yè)廣泛使用,必然有其可取之處,甚至可以說(shuō)Java EE這門技術(shù)造就了不少優(yōu)秀的程序員。

第1章:導(dǎo)論。

模式能夠:

利用一個(gè)經(jīng)過(guò)驗(yàn)證可行的解決方案;

提供一套通用詞匯;

約束解決方案的空間。

第2章:表現(xiàn)層設(shè)計(jì)考慮和不佳實(shí)踐

客戶端驗(yàn)證:基于表單的驗(yàn)證、基于抽象類型的驗(yàn)證。

曾經(jīng)在JSP中濫用過(guò)的助手類,通過(guò)助手類在頁(yè)面和業(yè)務(wù)邏輯之間傳遞數(shù)據(jù),有點(diǎn)類似于如今Struts中的Action作為傳值模型時(shí)的情況。

表現(xiàn)層不佳實(shí)踐:

多個(gè)視圖中都包含控制代碼;

表現(xiàn)層數(shù)據(jù)結(jié)構(gòu)暴露給業(yè)務(wù)層或者業(yè)務(wù)領(lǐng)域?qū)ο?,比如:暴露HTTPServletRequest;

重復(fù)提交表單;

敏感資源暴露給客戶端直接訪問(wèn),有個(gè)原則,敏感的東西不能放在WEB-INF之外;

胖控制器;

……

怎么區(qū)分后臺(tái)視圖層和前臺(tái)頁(yè)面層?或者說(shuō),怎么劃分哪些事情JSP或者模板做,哪些事情JavaScript做?首先,根據(jù)模型驅(qū)動(dòng)的原則,通常送到JSP或者模板上的都是通用模型的對(duì)象或者對(duì)象集,JSP或者模板根據(jù)需要選擇展示出來(lái),但是后續(xù)可抽取為不需和服務(wù)端交互狀態(tài)下響應(yīng)用戶的行為,應(yīng)當(dāng)劃分為JavaScript的工作。

第3章:業(yè)務(wù)層設(shè)計(jì)考慮和不佳實(shí)踐

session bean:根據(jù)EJB規(guī)范,每個(gè)session bean專門服務(wù)于一個(gè)客戶端或者用戶,生命時(shí)間等于客戶端會(huì)話時(shí)間;在服務(wù)器崩潰后無(wú)法存活、無(wú)法持久化、會(huì)超時(shí)、可以涉及事務(wù);支持構(gòu)造有狀態(tài)或無(wú)狀態(tài)的對(duì)話模型。

不過(guò)現(xiàn)在的容器會(huì)話大多可以持久化了,會(huì)話復(fù)制和會(huì)話持久化應(yīng)當(dāng)是會(huì)話管理中重要的兩個(gè)分支,通常情況下會(huì)話不需考慮完整的事務(wù)性,保證線程獨(dú)立性即可。

至于無(wú)狀態(tài)的session bean,可以被池化,以高效利用(EJB容器管理)。

entity bean:實(shí)體bean是否應(yīng)該包含業(yè)務(wù)邏輯?按照下面三個(gè)原則去判定,還是比較清晰的:

這樣的業(yè)務(wù)邏輯是否會(huì)引入實(shí)體之間的關(guān)系?比如處理UserInfo的時(shí)候,是否引入了AccountInfo,這樣應(yīng)當(dāng)考慮根據(jù)模型驅(qū)動(dòng)的原則,放置到專門的User或者Account相關(guān)的業(yè)務(wù)無(wú)狀態(tài)bean中去;

是否要負(fù)責(zé)管理用戶交互的工作流?

是否會(huì)擔(dān)負(fù)起本該屬于其他業(yè)務(wù)組件的責(zé)任?

有一個(gè)“是”,就說(shuō)明不該包含這段業(yè)務(wù)邏輯。

尤其提一句,如果使用遠(yuǎn)程實(shí)體bean,就更應(yīng)該減少實(shí)體bean之間的依賴關(guān)系,以提高性能和可用性。

業(yè)務(wù)層和集成層不佳實(shí)踐:

對(duì)象模型或關(guān)系模型或每個(gè)用例直接映射成實(shí)體bean:導(dǎo)致粒度過(guò)細(xì),EJB就給網(wǎng)絡(luò)傳輸帶來(lái)太多的負(fù)擔(dān);

通過(guò)getter、setter暴露EJB所有屬性:這也是不好的,提供少量和可控的方法調(diào)用,減少遠(yuǎn)程方法調(diào)用的開(kāi)銷;

客戶端中包括服務(wù)尋址代碼:尋址這件事情應(yīng)當(dāng)從單純的客戶端抽離出來(lái),把不同的尋址策略和復(fù)雜度封裝起來(lái),真正做到透明傳輸(擴(kuò)展到without EJB的系統(tǒng)中也一樣,集群環(huán)境中也一樣,把尋址的行為隱藏于業(yè)務(wù)邏輯之下)。

EJB用戶長(zhǎng)時(shí)間持續(xù)的事務(wù):會(huì)鎖住其他EJB需要的資源;

……

第4章:J2EE重構(gòu)

對(duì)業(yè)務(wù)層隱藏表現(xiàn)細(xì)節(jié):對(duì)用戶請(qǐng)求的處理和通信協(xié)議相關(guān)的數(shù)據(jù)不應(yīng)當(dāng)被業(yè)務(wù)層獲取,最簡(jiǎn)單的例子就是HttpServletRequest對(duì)象。

用session bean包裝entity bean:現(xiàn)在這里說(shuō)的問(wèn)題一般不會(huì)出現(xiàn),一般也不會(huì)有人直接把Action對(duì)象扔給后面的業(yè)務(wù)邏輯去處理,原文說(shuō)的解決辦法是引入業(yè)務(wù)代表,涉及到此的還有兩條:減少entity bean之間的通信;將業(yè)務(wù)邏輯移至session bean。

分離數(shù)據(jù)訪問(wèn)代碼:DAO。

按層重構(gòu)系統(tǒng)架構(gòu)(這里也正好歸納一下現(xiàn)在J2EE系統(tǒng)中常涉及到的Action、Service和EJB中的幾種bean的內(nèi)在聯(lián)系),例如:

客戶端層:瀏覽器

表現(xiàn)層:JSP、模板、業(yè)務(wù)代表

業(yè)務(wù)層:entity bean(Action)、session bean(各種粒度的Service)

集成層:DAO

資源層:DB

……

表現(xiàn)層模式

攔截過(guò)濾器:Intercepting Filter。正如圖中的“Apply zero or more”和Servlet規(guī)范所述一樣,應(yīng)當(dāng)具備一個(gè)鏈?zhǔn)浇Y(jié)構(gòu)。這個(gè)鏈?zhǔn)浇Y(jié)構(gòu)中的每個(gè)filter,互相之間應(yīng)當(dāng)是一個(gè)互不依賴的松耦合關(guān)系,以便于容易地組合。

前端控制器:Front Controller。給表現(xiàn)層請(qǐng)求安排一個(gè)集中訪問(wèn)點(diǎn)。集中了控制邏輯,一定程度避免了重復(fù)代碼。和攔截過(guò)濾器的區(qū)別:攔截過(guò)濾器使用的是松耦合的,結(jié)合成鏈?zhǔn)降奶幚砥鬟壿?,適合進(jìn)行強(qiáng)大的預(yù)處理、后處理的策略分布;而前端控制器則專注于集中控制,減少視圖中的業(yè)務(wù)和處理邏輯,提高重用度。

在常用的Struts網(wǎng)站構(gòu)架中,N個(gè)攔截器都是可以自由組合的,也可以自定義合適的攔截器棧來(lái)繼承某個(gè)通用的基礎(chǔ)攔截器棧,一些通用的攔截邏輯變放置在基礎(chǔ)攔截器棧中,這里是一個(gè)攔截過(guò)濾器和前端控制器結(jié)合實(shí)現(xiàn)的例子。

Context對(duì)象:不想在與協(xié)議無(wú)關(guān)的環(huán)境上下文中使用針對(duì)特定協(xié)議的系統(tǒng)信息。就是說(shuō)系統(tǒng)信息,比如請(qǐng)求、配置和安全數(shù)據(jù)等等,這些東西,通常應(yīng)當(dāng)被隱藏起來(lái),不能被業(yè)務(wù)邏輯看到;但是在某些情形下,業(yè)務(wù)組件可能又必須用到這些信息,例如,進(jìn)行終端適配的組件,需要用到HTTP報(bào)文中的一些header,那么直接使用會(huì)導(dǎo)致組件的靈活性和可重用性的下降,導(dǎo)致前一篇我提到的表現(xiàn)層數(shù)據(jù)結(jié)構(gòu)和業(yè)務(wù)層的緊耦合。

解決方法就是制定一個(gè)特定的API,將業(yè)務(wù)組件需要的部分通過(guò)API來(lái)包裝和篩選,而不是直接把表現(xiàn)層數(shù)據(jù)結(jié)構(gòu)直接暴露給它。這樣一來(lái),對(duì)于表現(xiàn)層的一些改變,比如協(xié)議等方面的改變,不會(huì)直接影響到業(yè)務(wù)組件的接口和運(yùn)行,只需要修正API的實(shí)現(xiàn)邏輯。

還有個(gè)什么好處?如果我需要測(cè)試業(yè)務(wù)層的邏輯,因?yàn)橛辛诉@樣一層特殊的API,我可以把整個(gè)表現(xiàn)層mock掉。

這里有一個(gè)應(yīng)用例子就是RequestContext對(duì)象,API只傳輸這個(gè),而不是具體的某一Request對(duì)象,對(duì)于復(fù)雜的請(qǐng)求層面被隔離掉,留下一個(gè)包裝好的上下文給后面的邏輯。

應(yīng)用控制器:集中地、模塊化地進(jìn)行操作管理和視圖管理。

操作管理:把輸入請(qǐng)求解析到一個(gè)操作(action),讓它處理該請(qǐng)求。

視圖管理:選定返回給客戶端的視圖,并把請(qǐng)求分派到這個(gè)視圖。

這兩點(diǎn)的應(yīng)用例子其實(shí)就是在struts-xxx.xml里面定義的配置,如同一個(gè)路標(biāo),對(duì)于出入視圖層的數(shù)據(jù)進(jìn)行方向上的導(dǎo)航。

舉例來(lái)說(shuō),它的實(shí)現(xiàn)經(jīng)常采用的策略是command對(duì)象的策略,命令對(duì)象的說(shuō)法具體可見(jiàn)GoF的那本經(jīng)典設(shè)計(jì)模式的書。

效果:把操作管理和視圖管理分離開(kāi)了,提高了模塊化程度;再一個(gè)這個(gè)導(dǎo)航的邏輯被抽取成為一處獨(dú)立的配置單獨(dú)維護(hù),方便擴(kuò)展。

視圖助手:View Helper。把視圖和相關(guān)處理邏輯分離開(kāi)。

這里需要先提及兩個(gè)重要的階段:視圖準(zhǔn)備階段:這是指請(qǐng)求被分配到一個(gè)具體的視圖上面;視圖創(chuàng)建階段:視圖根據(jù)從模型中取得的內(nèi)容來(lái)實(shí)例化自己。

因此使用視圖封裝顯示格式的代碼,而使用助手封裝視圖處理邏輯。助手在視圖和模型之間充當(dāng)了一個(gè)適配器的角色,同時(shí)也會(huì)做一些格式邏輯相關(guān)的處理。

一個(gè)很好的例子就是各種標(biāo)簽,包括自定義標(biāo)簽,比如一個(gè)時(shí)間格式化的標(biāo)簽,對(duì)于一個(gè)時(shí)間,在不同的環(huán)境下以不同的格式展示。

視圖助手終究是“視圖”的助手,它的核心始終是視圖,對(duì)于已經(jīng)生成了的成熟的具備一定模型的數(shù)據(jù),試圖助手協(xié)助將它們以某種合適的方式展示出來(lái),而不應(yīng)當(dāng)做復(fù)雜或具體的業(yè)務(wù)邏輯。

于是這里提出第一點(diǎn)需要注意,怎樣把視圖助手和后端的邏輯區(qū)分開(kāi)?視圖助手得到的數(shù)據(jù)應(yīng)當(dāng)是已經(jīng)成熟的一定模型化的數(shù)據(jù),需要做的是僅僅是做一些格式的處理,對(duì)展示效果的修正和增強(qiáng),并不做任何業(yè)務(wù)邏輯的相關(guān)事宜。

第二點(diǎn)需要注意,應(yīng)當(dāng)把視圖助手和JavaScript區(qū)分開(kāi)來(lái),前者在服務(wù)端完成,后者在客戶端完成:把處理邏輯從頁(yè)面中抽取出來(lái),一個(gè)重要原因就是要減少在頁(yè)面中直接暴露的實(shí)現(xiàn)細(xì)節(jié)。在實(shí)際開(kāi)發(fā)中,這二者之間的區(qū)分,常常帶來(lái)困擾。比如在模板或者JSP中使用if標(biāo)簽,還是在客戶端使用JavaScript來(lái)控制邏輯?我建議這里應(yīng)當(dāng)有一個(gè)區(qū)分的原則:這些邏輯是否屬于客戶端才能決策的頁(yè)面展示細(xì)節(jié)?如果是,就使用JavaScript來(lái)完成,反之還是應(yīng)當(dāng)隱藏到頁(yè)面助手中。

復(fù)合視圖:Composite View。使用由多個(gè)原子化的子視圖構(gòu)成的復(fù)合視圖。特點(diǎn)是組合是可以動(dòng)態(tài)的,而頁(yè)面布局又可以整體控制,和頁(yè)面內(nèi)容互相獨(dú)立。

有這么幾個(gè)常見(jiàn)的例子:Portlet就是一個(gè)復(fù)合視圖結(jié)合的最好例子,主題可以影響到所有視圖的呈現(xiàn),又是和展示的具體內(nèi)容沒(méi)有關(guān)系的,Portlet可以在服務(wù)端做到視圖的聚合,而不把事情遺留到客戶端完成,不涉及瀏覽器跨域的安全性問(wèn)題;SiteMesh是一個(gè)很適合對(duì)頁(yè)眉、頁(yè)腳等頁(yè)面通用元素拼裝的框架,比jsp:include標(biāo)簽優(yōu)雅;更小維度上,標(biāo)簽的引用也可以認(rèn)為是視圖的復(fù)合。

視圖的復(fù)合增進(jìn)了視圖模塊化和重用能力,這方面來(lái)看是增加了可維護(hù)能力;但是另一方面,一個(gè)完整的直觀的頁(yè)面被拆得七零八落,又降低了可維護(hù)性,為了解決這個(gè)問(wèn)題,我覺(jué)得對(duì)于一個(gè)大型Web應(yīng)用,一個(gè)好的思路是提供一種工具,至少是一個(gè)簡(jiǎn)易的指導(dǎo)方法,從頁(yè)面的某一部分元素快速定位到具體的最小視圖上;另外,視圖的復(fù)合帶來(lái)了服務(wù)端拆解和部署的靈活性,但一定也帶來(lái)性能損耗,Portlet聚合尤為明顯。

還有一個(gè)重要的事項(xiàng)是,頁(yè)面布局需要和頁(yè)面內(nèi)容相獨(dú)立。一個(gè)較大的視圖拆解成若干個(gè)小的子視圖,這些小的子視圖應(yīng)當(dāng)具備獨(dú)立的展示內(nèi)容,但是頁(yè)面的布局不應(yīng)當(dāng)有其中的任一子視圖控制,而可以落到某一個(gè)整體的主題定義中去。

服務(wù)到工作者:Service To Worker。集中控制權(quán)管理和請(qǐng)求的處理,再把控制權(quán)交給視圖之前獲取表現(xiàn)模型。視圖則根據(jù)獲得的表現(xiàn)模型生成一個(gè)動(dòng)態(tài)響應(yīng)。這個(gè)模式是由前端控制器、應(yīng)用控制器和視圖助手組合而成的。具體說(shuō):前端控制器集中了訪問(wèn)視圖的邏輯,然后應(yīng)用控制器完成了視圖導(dǎo)航,最后由視圖助手協(xié)助準(zhǔn)備了視圖所使用的模型數(shù)據(jù)。

分配器視圖:Dispatcher View。把視圖本身作為請(qǐng)求的最初訪問(wèn)點(diǎn),把業(yè)務(wù)處理的邏輯交由視圖完成。

服務(wù)到工作者和分配器視圖是非常類似的兩種模式,前者以進(jìn)視圖前的邏輯處理為核心,后者才真正以視圖為核心。當(dāng)業(yè)務(wù)處理比較簡(jiǎn)單,或者不能合適地通過(guò)視圖之外的邏輯來(lái)控制時(shí),可以采用分配器視圖模式,把控制邏輯放到視圖中。在這種方式下,不代表分配器視圖做了所有的業(yè)務(wù)邏輯,對(duì)于數(shù)據(jù)的準(zhǔn)備完全可以在進(jìn)視圖之前完成,畢竟視圖中完成大量的業(yè)務(wù)邏輯通常不是一個(gè)優(yōu)秀的解決方案。

一個(gè)很好的例子就是頁(yè)面集成,進(jìn)入集成頁(yè)之前準(zhǔn)備好集成的子頁(yè)面的URL,到了集成的父頁(yè)面中再執(zhí)行拼裝操作,這個(gè)行為,甚至可能被到客戶端才完成。這種情形下,盡管頁(yè)面去做了聚合視圖的事,但這恰恰是頁(yè)面最擅長(zhǎng)的行為,比進(jìn)頁(yè)面之前把數(shù)據(jù)準(zhǔn)備好、拼裝好再一并寫入頁(yè)面要可見(jiàn)和可接受得多。

業(yè)務(wù)層模式

業(yè)務(wù)代表:Business Delegate。封裝對(duì)業(yè)務(wù)服務(wù)的訪問(wèn),隱藏服務(wù)層具體實(shí)現(xiàn)細(xì)節(jié),主要為降低客戶端和服務(wù)層之間的耦合。除了隱藏服務(wù)細(xì)節(jié)、處理服務(wù)異常等基礎(chǔ)功能以外,還可以做服務(wù)的緩存。業(yè)務(wù)代表是客戶端的直接客戶,起到客戶端業(yè)務(wù)抽象層的作用,而業(yè)務(wù)代表的另一頭,常常連接著會(huì)話門面。

比較常用的情況就是在某種遠(yuǎn)程連接和業(yè)務(wù)處理的基礎(chǔ)上,使用業(yè)務(wù)代表把這些細(xì)節(jié)統(tǒng)統(tǒng)包裝起來(lái),給內(nèi)部提供的模型也好API也好,都是和外部接口相異的。比如一個(gè)系統(tǒng)中對(duì)于展現(xiàn)的內(nèi)容數(shù)據(jù)的同步,以及訂購(gòu)、使用等業(yè)務(wù)流程,都由SOAP消息載體來(lái)協(xié)助完成,那么封裝起SOAP消息這種底層行為的PCMP模塊,對(duì)其上內(nèi)部組件暴露的都是系統(tǒng)中通用的模型和API,將SOAP定義的模型和相應(yīng)的同步、校驗(yàn)和通知行為等隔離開(kāi)了。

服務(wù)定位器:Service Locator。封裝對(duì)服務(wù)和組件的尋址。在系統(tǒng),尤其是分布式系統(tǒng)中,服務(wù)通常被設(shè)置為可插接的,通過(guò)某種方式掛在服務(wù)總線上,尋求某服務(wù)的行為應(yīng)當(dāng)對(duì)服務(wù)的使用者來(lái)說(shuō)透明。

某個(gè)大型解決方案中,某一組件充當(dāng)SOA中的ESB,承擔(dān)了服務(wù)定位的角色,派發(fā)往各個(gè)服務(wù)不同協(xié)議的請(qǐng)求,皆可以統(tǒng)一的協(xié)議收攏到該組件中,再由該組件負(fù)責(zé)以各種方式分發(fā)給不同的服務(wù)。

會(huì)話門面:Session Facade。目的有二:控制客戶端對(duì)業(yè)務(wù)對(duì)象的訪問(wèn);降低客戶端和細(xì)粒度業(yè)務(wù)組件訪問(wèn)的網(wǎng)絡(luò)負(fù)載。只暴露必要的、粗粒度的服務(wù),并且可以對(duì)之在門面內(nèi)部做好事務(wù)、安全、尋址和記錄等等切面輔助工作。

多數(shù)情況下使用無(wú)狀態(tài)的會(huì)話門面,對(duì)于客戶端要求也較低,通常只需要單次調(diào)用就能完成功能;但也可能需要使用有狀態(tài)的會(huì)話門面,通常比較復(fù)雜,需要涉及會(huì)話事務(wù)、會(huì)話資源的管理和釋放。

和業(yè)務(wù)代表的關(guān)系:業(yè)務(wù)代表在客戶端提供了對(duì)會(huì)話門面的抽象,把客戶端的請(qǐng)求分別代理給專門提供特定服務(wù)的會(huì)話門面。

應(yīng)用服務(wù):集中、聚合特定功能,提供一個(gè)統(tǒng)一的服務(wù)層,其接口粒度比服務(wù)門面細(xì)。服務(wù)門面通常包括很少,甚至不包括業(yè)務(wù)邏輯,僅僅提供一個(gè)簡(jiǎn)單和粗粒度的接口。而一些相關(guān)的操作,之間具有內(nèi)聚性,這就需要某個(gè)角色把它們聚合起來(lái)。

Facade成為粗粒度的門面的時(shí)候,內(nèi)部就由多個(gè)細(xì)粒度的Service組成,這就是會(huì)話門面和應(yīng)用服務(wù)之間的關(guān)系。舉一個(gè)更具體的例子,一個(gè)短信息發(fā)送的會(huì)話門面,提供了消息發(fā)送的一系列功能,內(nèi)部則包含了若干個(gè)應(yīng)用服務(wù):拼裝消息報(bào)文、消息事務(wù)信息持久化、發(fā)送消息。合理地分割和規(guī)劃應(yīng)用服務(wù)是降低會(huì)話門面復(fù)雜度的有效途徑。

業(yè)務(wù)對(duì)象:利用對(duì)象模型把業(yè)務(wù)數(shù)據(jù)和業(yè)務(wù)邏輯分離開(kāi)來(lái)。業(yè)務(wù)對(duì)象在最前端(客戶端)和最后端(數(shù)據(jù)資源)都會(huì)進(jìn)行業(yè)務(wù)數(shù)據(jù)形式的轉(zhuǎn)化。業(yè)務(wù)對(duì)象的實(shí)現(xiàn)通常有兩種方式:POJO + JDO 或者 Entity Bean + BMP/CMP。業(yè)務(wù)對(duì)象包含業(yè)務(wù)邏輯和業(yè)務(wù)狀態(tài)。

J2EE系統(tǒng)中面向過(guò)程向面向?qū)ο筠D(zhuǎn)變有時(shí)甚至僅僅區(qū)別于最初的一念之差。沒(méi)有什么是絕對(duì)的事情,如果業(yè)務(wù)非常簡(jiǎn)單,客戶端通過(guò)淺淺的顯示層,直接訪問(wèn)持久層、甚至數(shù)據(jù)資源存儲(chǔ)中業(yè)務(wù)數(shù)據(jù),整個(gè)過(guò)程中,其結(jié)構(gòu)都是依據(jù)客戶端所需數(shù)據(jù)的獲取過(guò)程來(lái)完成的,是典型的面向過(guò)程的實(shí)現(xiàn)方式,沒(méi)有什么不合理;但一旦情況復(fù)雜了,你也許希望在系統(tǒng)中設(shè)定一些核心的業(yè)務(wù)模型,讓它們來(lái)驅(qū)動(dòng)整個(gè)服務(wù)的提供和流程的運(yùn)轉(zhuǎn),而不再是客戶端無(wú)任何包裝的需求,這時(shí)候興許就變成了模型驅(qū)動(dòng)下的面向?qū)ο笮袨椤?/p>

復(fù)合實(shí)體:Composite Entity。結(jié)合本地entity bean和POJO,實(shí)現(xiàn)業(yè)務(wù)對(duì)象持久化。復(fù)合實(shí)體能夠把一組相互關(guān)聯(lián)的業(yè)務(wù)對(duì)象聚合為粗粒度的entity bean實(shí)現(xiàn)。業(yè)務(wù)對(duì)象被實(shí)現(xiàn)為父對(duì)象和從屬對(duì)象,從屬對(duì)象緊耦合與父對(duì)象,且無(wú)法獨(dú)立存在或獨(dú)立被訪問(wèn)、識(shí)別和管理。無(wú)論使用遠(yuǎn)程對(duì)象還是本地對(duì)象實(shí)現(xiàn)復(fù)合實(shí)體,都不應(yīng)該直接把entity bean暴露給客戶端,而應(yīng)當(dāng)封裝在門面里面。

實(shí)際我們的項(xiàng)目中,給內(nèi)容超市部分,封裝了核心的API,而API的調(diào)用傳值,都是通過(guò)復(fù)合實(shí)體——各種Event完成的。這是一個(gè)很好的例子,就算日后將API擴(kuò)展成可遠(yuǎn)程調(diào)用的方法,性質(zhì)并未改變。

臟數(shù)據(jù)標(biāo)示器策略:對(duì)復(fù)合實(shí)體持久化的時(shí)候,如果能判斷哪些從屬對(duì)象是臟的,就可以提高持久化性能。

傳輸策略可以考慮單次傳輸整個(gè)復(fù)合實(shí)體,減少網(wǎng)絡(luò)交互;可以結(jié)合臟數(shù)據(jù)標(biāo)示器,只傳輸變化的部分;可以結(jié)合懶加載策略,只傳輸需要的部分。

傳輸對(duì)象:Transfer Object??鐚哟蝹鬏敹喾N數(shù)據(jù)元素。有一種簡(jiǎn)化遠(yuǎn)程對(duì)象和遠(yuǎn)程接口的方法是,把眾多get/set方法合并成粗粒度的getDate和setData方法。我們通常希望傳輸對(duì)象是簡(jiǎn)單和可控的,因此粒度不應(yīng)過(guò)細(xì),細(xì)節(jié)應(yīng)盡量屏蔽,對(duì)于接口的定義,應(yīng)該盡少約束。

日后我們系統(tǒng)的API擴(kuò)展必然面臨著復(fù)合實(shí)體傳輸?shù)那榫?,API的遠(yuǎn)程調(diào)用已漸漸變得廣泛,比如JavaEye支持API調(diào)用,使用JSON作為數(shù)據(jù)形式;我們常用的Blog客戶端也是遵從的簡(jiǎn)約的API規(guī)范開(kāi)發(fā)的。

傳輸對(duì)象組裝器:Transfer Object Assembler。復(fù)合傳輸對(duì)象的形式構(gòu)建應(yīng)用模型。從各種不同的業(yè)務(wù)組件和業(yè)務(wù)服務(wù)中聚合多個(gè)傳輸對(duì)象,并且最后把復(fù)合對(duì)象返回給客戶端。最大的好處:減少了客戶端和應(yīng)用模型之間的耦合。對(duì)于不同的傳輸形式,就并不需要應(yīng)用模型做任何的改變,搭配不同的傳輸對(duì)象組裝器和傳輸策略即可。

系統(tǒng)的頁(yè)面集成中涉及到的會(huì)話信息的傳遞,提供了幾種策略,就涉及到SpringHTTPInvoker傳輸、OSCache傳輸、本地傳輸和void傳輸?shù)认鄳?yīng)的對(duì)象組裝器。

值列表處理器:Value List Handler。執(zhí)行查詢、緩存結(jié)果,并讓客戶端遍歷、選擇查詢結(jié)果?;旧舷喈?dāng)于封裝了一個(gè)游標(biāo),共客戶端遍歷操作,但是如果這個(gè)游標(biāo)是遠(yuǎn)程的,注意可能造成巨大的性能消耗。

我們的系統(tǒng)中設(shè)計(jì)了一個(gè)類:PaginationSupport,用于分頁(yè),其角色便類似于值列表處理器。需要查詢哪一塊區(qū)域的數(shù)據(jù)集合,就傳遞相應(yīng)的游標(biāo)指令。

集成層模式:

數(shù)據(jù)訪問(wèn)對(duì)象:Data Access Object。提煉和封裝對(duì)持久化存儲(chǔ)介質(zhì)的訪問(wèn)。DAO封裝了數(shù)據(jù)源的實(shí)現(xiàn)細(xì)節(jié),總是面向API調(diào)用者提供統(tǒng)一的接口。DAO應(yīng)當(dāng)被實(shí)現(xiàn)為無(wú)狀態(tài)的對(duì)象,這樣就可以成為輕量的對(duì)象,不需要考慮線程、同步、緩存等問(wèn)題,而把這些問(wèn)題下沉到數(shù)據(jù)層去完成。

以我參與的項(xiàng)目的緩存的使用舉例,模型DAO并不做任何的緩存行為,數(shù)據(jù)庫(kù)使用自身的緩存能力,并且在必要時(shí)冗余字段,這是基于數(shù)據(jù)粒度的基礎(chǔ)緩存;到了調(diào)用DAO的業(yè)務(wù)層面,比如Service層,才進(jìn)行業(yè)務(wù)模型粒度的緩存,比如緩存某些用戶對(duì)象等;而DAO層實(shí)現(xiàn)了基礎(chǔ)DAO的約束,繼承了Spring給DAO封裝的基礎(chǔ)能力,比如事務(wù)控制的能力等,所有方法都不使用類狀態(tài)變量,找不到任何對(duì)用戶會(huì)話對(duì)象訪問(wèn)的邏輯,也看不到任何java.sql包內(nèi)的類和對(duì)象(尤其是異常)。

服務(wù)激活器:Service Activator。用于接收異步請(qǐng)求,由異步請(qǐng)求來(lái)觸發(fā)業(yè)務(wù)。JMS監(jiān)聽(tīng)器是一個(gè)常用的實(shí)現(xiàn)者,JMS目標(biāo)通常有兩種,一種是主題,即Topic,用于點(diǎn)對(duì)面的通知;一種是隊(duì)列,即Queue,用于點(diǎn)對(duì)點(diǎn)的通知。

解決方案中的請(qǐng)求通常都由界面?zhèn)扔|發(fā),因此服務(wù)激活器通常被放置在內(nèi)部部件(例如計(jì)費(fèi)部件)上,計(jì)費(fèi)業(yè)務(wù)的請(qǐng)求由展現(xiàn)部件經(jīng)過(guò)總線轉(zhuǎn)發(fā)給計(jì)費(fèi)部件觸發(fā)計(jì)費(fèi)服務(wù)流程。

業(yè)務(wù)領(lǐng)域存儲(chǔ):將持久化邏輯從對(duì)象模型中分離出去。比如最常用的BMP和CMP,無(wú)需根據(jù)不同的業(yè)務(wù)對(duì)象類型建立不同的數(shù)據(jù)庫(kù)腳本,只需要維護(hù)好業(yè)務(wù)領(lǐng)域側(cè)的模型配置,存儲(chǔ)事件是透明的。

業(yè)務(wù)領(lǐng)域存儲(chǔ)的實(shí)現(xiàn)有很多種方式,比如Grails內(nèi)部使用規(guī)約配置和Hibernate的持久化管理能力,讓存儲(chǔ)的邏輯完全透明,映射關(guān)系的配置和映射表建表和CRUD的sql語(yǔ)句都可以由規(guī)約代替,于是可以不進(jìn)行任何的映射配置來(lái)實(shí)現(xiàn)存儲(chǔ),真正做到透明存儲(chǔ)。

再比如:上述的關(guān)系型數(shù)據(jù)庫(kù)下,數(shù)據(jù)庫(kù)表和業(yè)務(wù)模型是有映射關(guān)系的,也就是常說(shuō)的橫表;但是也可以使用縱表,實(shí)現(xiàn)數(shù)據(jù)模型的任意擴(kuò)展,這就是一個(gè)通過(guò)改變存儲(chǔ)方式來(lái)實(shí)現(xiàn)持久化邏輯完全不依賴于對(duì)象模型的例子。

使用nosql,海量數(shù)據(jù)的存儲(chǔ)可以是稀疏的,水平擴(kuò)展性、查詢性能優(yōu)異,它減弱了數(shù)據(jù)之間在存儲(chǔ)層面上相互之間的約束。

Web Service中轉(zhuǎn):暴露可通過(guò)XML和web協(xié)議訪問(wèn)的服務(wù),并將對(duì)服務(wù)的請(qǐng)求轉(zhuǎn)發(fā)給真實(shí)的服務(wù)組件。通常有許多Web Service是不希望暴露出來(lái)的,有時(shí)有一些服務(wù)又需要聚合起來(lái)使用,這時(shí)候就需要Web Service中轉(zhuǎn)。在使用中轉(zhuǎn)前的Web Service需要被改造,以支持中轉(zhuǎn)的接口(例如一個(gè)本地接口)。這個(gè)模式和Facade很類似,只不過(guò)它的定位放在了遠(yuǎn)程接口上。

微架構(gòu):一組被同時(shí)使用的模式,用于實(shí)現(xiàn)系統(tǒng)中的一個(gè)特定部分(子系統(tǒng))。每一個(gè)微架構(gòu)是獨(dú)立和內(nèi)聚的積木塊,由它們構(gòu)成整個(gè)系統(tǒng)的架構(gòu)。微架構(gòu)有多種形式,比如Web Worker工作流。

工作流可以把業(yè)務(wù)邏輯和過(guò)程邏輯分離開(kāi),使得關(guān)注點(diǎn)和階段清晰和分散。本人當(dāng)前參與的項(xiàng)目是一個(gè)較大的Web項(xiàng)目,處于整個(gè)解決方案的前端,但是里面并未明確提及工作流(盡管在解決方案的后端,計(jì)費(fèi)部件和內(nèi)容管理部件中明確定義和使用了)。首先要說(shuō)的是,作為一個(gè)展現(xiàn)部件,對(duì)于用戶操作的過(guò)程中個(gè),并不適合具備過(guò)多的用戶交互途徑,通常也不會(huì)有特別繁雜的業(yè)務(wù)邏輯;但是倘若整個(gè)項(xiàng)目的內(nèi)容使用部分流程過(guò)于復(fù)雜,完全可以引入工作流的思想解決問(wèn)題。

以一個(gè)展現(xiàn)系統(tǒng)中播放的內(nèi)容使用的流程為例,第一次交互行為prePlay,發(fā)起播放行為,系統(tǒng)給用戶返回一個(gè)產(chǎn)品確認(rèn)頁(yè)面;用戶確認(rèn)并發(fā)起第二次交互行為play,系統(tǒng)給用戶完成訂購(gòu)操作并生成播放的rtsp鏈接回送給用戶;第三次用戶使用此rtsp鏈接和播放系統(tǒng)交互。這三次主流程的交互中,所有交互行為都由用戶出發(fā)(這是通常是展現(xiàn)系統(tǒng)的工作流步驟中的特點(diǎn)),并且只有前兩步和展現(xiàn)系統(tǒng)相關(guān)。每一個(gè)步驟都具備獨(dú)立的攔截器棧,相應(yīng)的Action-Service-DAO方法。在某些業(yè)務(wù)復(fù)雜的系統(tǒng)中,工作流的步驟是可以自定義的,即用戶可以自行組裝工作流——這樣的定制屬于縱向業(yè)務(wù)流程的定制,與橫向的API調(diào)用的定制相異。

通常我們使用request-session-application這樣三類容器管理當(dāng)前數(shù)據(jù),但是在request scope(一次交互的數(shù)據(jù)存放)和session scope(用戶會(huì)話數(shù)據(jù)存放)對(duì)象之間,還可以引入flash scope(N次交互的數(shù)據(jù)存放,由攔截器管理)和work flow scope(一個(gè)完整業(yè)務(wù)流程的數(shù)據(jù)存放,由工作流引起管理)對(duì)象。

好了同學(xué)們,我能介紹的也都全部介紹完給你們了,以上的部分就是我想說(shuō)的內(nèi)容,如果你也想在IT行業(yè)拿高薪,可以參加我們的訓(xùn)練營(yíng)課程,選擇最適合自己的課程學(xué)習(xí),技術(shù)大牛親授,7個(gè)月后,進(jìn)入名企拿高薪。我們的課程內(nèi)容有:Java工程化、高性能及分布式、高性能、深入淺出。高架構(gòu)。性能調(diào)優(yōu)、Spring,MyBatis,Netty源碼分析和大數(shù)據(jù)等多個(gè)知識(shí)點(diǎn)。如果你想拿高薪的,想學(xué)習(xí)的,想就業(yè)前景好的,想跟別人競(jìng)爭(zhēng)能取得優(yōu)勢(shì)的,想進(jìn)阿里面試但擔(dān)心面試不過(guò)的,你都可以來(lái),群號(hào)為:658362658

注:加群要求

1、具有1-5工作經(jīng)驗(yàn)的,面對(duì)目前流行的技術(shù)不知從何下手,需要突破技術(shù)瓶頸的可以加。

2、在公司待久了,過(guò)得很安逸,但跳槽時(shí)面試碰壁。需要在短時(shí)間內(nèi)進(jìn)修、跳槽拿高薪的可以加。

3、如果沒(méi)有工作經(jīng)驗(yàn),但基礎(chǔ)非常扎實(shí),對(duì)java工作機(jī)制,常用設(shè)計(jì)思想,常用java開(kāi)發(fā)框架掌握熟練的,可以加。

4、覺(jué)得自己很牛B,一般需求都能搞定。但是所學(xué)的知識(shí)點(diǎn)沒(méi)有系統(tǒng)化,很難在技術(shù)領(lǐng)域繼續(xù)突破的可以加。

5.阿里Java高級(jí)大牛直播講解知識(shí)點(diǎn),分享知識(shí),多年工作經(jīng)驗(yàn)的梳理和總結(jié),帶著大家全面、科學(xué)地建立自己的技術(shù)體系和技術(shù)認(rèn)知!

作者:四火,Amazon程序員 全棧工程師 @西雅圖

鏈接:http://www.raychase.net/161?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容