EJB的七年之癢 |
曾幾何時(shí),EJB被人們當(dāng)作J2EE的核心而頂禮膜拜??上?,過(guò)去七年的經(jīng)驗(yàn)退去了EJB的光環(huán)。我現(xiàn)在更多的把EJB當(dāng)作一種過(guò)渡性技術(shù):它普及了很多有價(jià)值的思想;但對(duì)于大多數(shù)新的應(yīng)用來(lái)說(shuō)。它并不是最佳的選擇。
EJB的原意是簡(jiǎn)化企業(yè)應(yīng)用的開(kāi)發(fā),讓應(yīng)用開(kāi)發(fā)人員將注意力集中于他們的問(wèn)題領(lǐng)域和編寫業(yè)務(wù)邏輯。而不是去關(guān)注系統(tǒng)的問(wèn)題。同時(shí),EJB規(guī)范也承諾EJB(以及基于EJB的應(yīng)用)在不同AppServer之間的可移植性。那么這些期望達(dá)到了嗎?
一個(gè)過(guò)時(shí)的組件模型
1998年3月,當(dāng)EJB第一次出現(xiàn)時(shí),在企業(yè)軟件領(lǐng)域根本沒(méi)有標(biāo)準(zhǔn)。微軟事務(wù)服務(wù)器(MTS)可能是最接近一個(gè)企業(yè)組件框架的東西,但它是廠商專有的,而且依賴于微軟C++和其他語(yǔ)言并不優(yōu)雅的擴(kuò)展,并且緊密綁定在COM/DCOM上。
在這樣的環(huán)境下,EJB看起來(lái)即簡(jiǎn)單又開(kāi)放。然而,隨后幾年的技術(shù)發(fā)展,使得EJB不再象當(dāng)初那樣具有獨(dú)到的優(yōu)勢(shì)。
Java語(yǔ)言的規(guī)范
EJB1.0規(guī)范是在Java1.2對(duì)API進(jìn)行重大改進(jìn)之前6個(gè)月發(fā)布的。J2SE1.3又對(duì)Java進(jìn)行了更為重大的改進(jìn)。例如動(dòng)態(tài)代理(dynamic proxy),它使得任何接口可以被一個(gè)運(yùn)行時(shí)生成的代理所實(shí)現(xiàn)。有了這樣的能力,EJB所采用的那種”不完全匹配組件接口”的實(shí)現(xiàn)方式看起來(lái)越發(fā)的笨拙,要求一個(gè)專門的部署階段也同樣值得懷疑;實(shí)際上,很多EJB容器廠商很快利用動(dòng)態(tài)代理的先進(jìn)技術(shù)取消了代碼生成和編譯的步驟。而這正是EJB部署過(guò)程中的重要一環(huán)。看起來(lái),大多數(shù)廠商都同意:session bean不再需要代碼生成的支持,只有entity bean才有必要。
.NET的挑戰(zhàn)
EJB最初的靈感部分來(lái)自于MTS。不過(guò)EJB的吸引力比MTS可要大得多。在EJB的大部分時(shí)間里,微軟缺乏一個(gè)可信任的企業(yè)架構(gòu),COM/DCOM和MTS都無(wú)法令人信服。EJB在這個(gè)領(lǐng)域基本上無(wú)人競(jìng)爭(zhēng)。
2002年初,隨著雄心勃勃的微軟.NET企業(yè)平臺(tái)的發(fā)布,情況發(fā)生了改變。.NET受J2EE的影響頗深。微軟從J2EE專家這里汲取了大量知識(shí)。同時(shí),.NET又與J2EE有一些顯著的差異,特別值得一提的是與EJB的差異。
.NET模糊了web容器和ejb容器之間的區(qū)別,而這兩種容器恰好是”經(jīng)典”j2EE架構(gòu)的根本。任何一種.NET語(yǔ)言中的對(duì)象都可以通過(guò)繼承ServicedComponent來(lái)使用企業(yè)級(jí)服務(wù),這里沒(méi)有獨(dú)立于受控環(huán)境的特殊”容器”。這意味著任何對(duì)象都可以享受企業(yè)級(jí)服務(wù),而不需要特殊的部署階段,也無(wú)須在開(kāi)發(fā)時(shí)承擔(dān)那么沉重的包袱。(我并不欣賞”強(qiáng)制繼承ServicedComponent”的做法,但那也好過(guò)實(shí)現(xiàn)一個(gè)EJB。 部署這樣一個(gè)”享受企業(yè)級(jí)服務(wù)的組件”比部署EJB簡(jiǎn)單多了。因?yàn)?/font>.NET也炮擊了j2EE中的很多外部部署描述文件。比如說(shuō),對(duì)于用于聲明性事務(wù)管理的元數(shù)據(jù),.NET不是將它們放在獨(dú)立的XML部署描述文件(例如ejb-jar.xml)中,而是以”元數(shù)據(jù)屬性”的形式存放在實(shí)際的組件源程序中。(代碼重構(gòu)不會(huì)破壞源碼級(jí)元數(shù)據(jù),這正是外部部署描述文件的一個(gè)重大缺陷。
在j2EE社區(qū),關(guān)于J2EE和.NET的爭(zhēng)吵從來(lái)未斷,而且全部都是毫無(wú)價(jià)值的老調(diào)重彈。幸運(yùn)的是,J2EE社區(qū)中的一些重要的推動(dòng)者們顯示出了一種開(kāi)明的態(tài)度,他們?cè)敢獠捎靡恍?/font>.NET所開(kāi)創(chuàng)的有價(jià)值的特性,例如:
Java1.5為Java添加源碼級(jí)元數(shù)據(jù),以及C#風(fēng)格的autoboxing功能。 JBoss4采用了.NET風(fēng)格的元數(shù)據(jù)來(lái)驅(qū)動(dòng)企業(yè)服務(wù)。 Spring和其他AOP框架(除了JBoss AOP之外)也使用了源碼級(jí)元數(shù)據(jù)。 EJB3.0采用源碼級(jí)元數(shù)據(jù)來(lái)描述目前保存在XML EJB部署描述文件中的信息。
Web Service
在EJB1.0和1.1的年代,除了Java自己的RMI/RMP之外,重要的分布式對(duì)象技術(shù)就只有CORBA和COM/DCOM了(這兩種技術(shù)很復(fù)雜,都沒(méi)有被業(yè)界大量采用)。相比之下,EJB更加簡(jiǎn)單,概念更加一致。因此它成功地在很多系統(tǒng)中引入了分布式對(duì)象。 如今,情況已經(jīng)大不相同了,基于XML的web service提供了比過(guò)去大得多的開(kāi)放性,這是真正的互操作,不僅僅是在微軟技術(shù)和基于Java的解決方案之間,還可以在多種語(yǔ)言和系統(tǒng)之間實(shí)現(xiàn)互操作。同時(shí),越來(lái)越多的人認(rèn)識(shí)到,分布式對(duì)象的使用僅僅在少數(shù)應(yīng)用中才是適合的。因此,快速增長(zhǎng)的領(lǐng)域是在異構(gòu)平臺(tái)之間的互操作性,而不是J2EE應(yīng)用服務(wù)器之間的遠(yuǎn)程調(diào)用。
敏捷方法學(xué)的興起
自從EJB在1998年誕生之后,開(kāi)發(fā)過(guò)程和最佳實(shí)踐的思想發(fā)生了重大變化。可能最重要的事件就是”敏捷”方法學(xué)的興起,例如極限編程(eXtreme Programing)。 尤其值得一提的是,測(cè)試先行的開(kāi)發(fā)(test first development),或者至少是嚴(yán)格的單元測(cè)試,其價(jià)值在很多項(xiàng)目中得到了證實(shí)。而EJB使得有效的unit test非常困難,因?yàn)?/font>EJB嚴(yán)重依賴容器的服務(wù)。因此這就意味著EJB使得敏捷開(kāi)發(fā)過(guò)程難以被應(yīng)用。
從未出現(xiàn)的組件市場(chǎng)
我們對(duì)EJB的失望還在于它沒(méi)能成功地創(chuàng)造一個(gè)第三方組件市場(chǎng),而這是其承諾的主要愿景之一(還記得EJB規(guī)范所設(shè)想的,將多個(gè)廠商提供的EJB”組裝”起來(lái)構(gòu)成應(yīng)用程序得情況嗎?)。 這個(gè)組件市場(chǎng)并沒(méi)有出現(xiàn),它是否真的會(huì)出現(xiàn)也很值得懷疑。之所以這樣,一部分是因?yàn)?/font>EJB的模型(可移植性有缺陷,部署也過(guò)于復(fù)雜),然而更重要的是企業(yè)組件太過(guò)復(fù)雜,有太多的依賴關(guān)系需要包裝。
方興未艾的新范式AOP
最后不得不提的是,一種新的編程模型正在浮出水面,那是一種更為通用的解決方案。僅僅其中的一部分就能夠提供EJB大多數(shù)有價(jià)值的能力,那就是面向切面編程(Aspect Oriented Programming).在J2EE中,我們主要用到AOP的攔截(interception)能力。它為我們提供了”在任何對(duì)象的方法調(diào)用前/后加入自定義行為”的能力。這使得我們可以處理企業(yè)應(yīng)用中的橫切(crosscutting)關(guān)注點(diǎn)(同時(shí)作用于多個(gè)對(duì)象的關(guān)注點(diǎn))。例如我們使用AOP可以把”與事務(wù)管理相關(guān)的重復(fù)勞動(dòng)”放進(jìn)一個(gè)框架內(nèi);另外一個(gè)很適合使用AOP的場(chǎng)合則是自定義安全檢查。
EJB為我們提供了什么
有經(jīng)驗(yàn)的系統(tǒng)架構(gòu)師傾向于只使用EJB的一小部分。毫無(wú)爭(zhēng)議SLSB(stateless session bean)是EJB中最有用的,然后是message-driven bean(用于異步操作)。Entity bean則可能是EJB規(guī)范中最虛弱的部分。它的性能相當(dāng)差,并且沒(méi)有解決好ORM最重要的問(wèn)題。
為什么SLSB如此流行?因?yàn)樗呛?jiǎn)單的組件,并且對(duì)一些企業(yè)系統(tǒng)常見(jiàn)的問(wèn)題提供了一個(gè)相當(dāng)好的解決方案。下面,讓我們逐一審視SLSB提供的主要服務(wù):
聲明式事務(wù)管理 SLSB最有價(jià)值的服務(wù)可能就是容器管理的事務(wù)CMT了。盡管最終通過(guò)JTS/JTA協(xié)調(diào)事務(wù)的是J2EE服務(wù)器而不是EJB容器,但SLSB讓我們可以使用聲明性,而非編程性的事務(wù)管理。(當(dāng)然如果想要回滾事務(wù),我要需要使用EJB API,但是在理想的狀態(tài)下我們不必為事務(wù)管理寫一行代碼)。 盡管EJB CMT對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō)很有價(jià)值,但要處理一些復(fù)雜的事務(wù)管理問(wèn)題就顯得力不從心了。(比如說(shuō),有時(shí)一個(gè)業(yè)務(wù)操作需要多個(gè)事務(wù),如果每次事務(wù)都通過(guò)一個(gè)EJB入口點(diǎn)調(diào)用一個(gè)EJB方法,這就比通過(guò)編程方式界定事務(wù)更復(fù)雜了。樂(lè)觀的鎖定策略也會(huì)成為一個(gè)問(wèn)題。如果我們使用聲明性事務(wù)來(lái)驅(qū)動(dòng)一種持久技術(shù)執(zhí)行樂(lè)觀事務(wù),樂(lè)觀并發(fā)異常將在容器提交事務(wù)之后才出現(xiàn),而此時(shí)應(yīng)用代碼已經(jīng)將控制權(quán)交給了EJB容器,很難重新控制程序的運(yùn)轉(zhuǎn)。EJB沒(méi)有為這類更復(fù)雜的場(chǎng)景提供良好的支持。如果使用Bean管理事務(wù)(BMT)的EJB,則需要從JNDI得到JTA User Transation的對(duì)象,然后直接使用JTA API。在同一個(gè)EJB中混合BMT和CMT也是不可能的。
因此,可以同時(shí)適應(yīng)高端和低端的輕量級(jí),更少侵入性的事務(wù)基礎(chǔ)架構(gòu)才是真正的價(jià)值所在。例如Spring框架提供的基于AOP的聲明性事務(wù)管理可以通過(guò)配置,在支持多個(gè)數(shù)據(jù)庫(kù)的JTA或者JDBC或者其他的特定于資源的事務(wù)管理API(例如JDO事務(wù)API)之間切換,而不需要對(duì)業(yè)務(wù)代碼做任何修改。 而且,EJB CMT還可以做得更加靈活。只有當(dāng)業(yè)務(wù)方法拋出一個(gè)unchecked異常時(shí),EJB容器才會(huì)回滾事務(wù)。這樣的處理方式不是我們通常希望的,如果能夠指定”哪些unchecked異??梢灾苯佑|發(fā)事務(wù)回滾”就更好了(這樣的自動(dòng)回滾將不被視為程序錯(cuò)誤)。Spring的聲明性事務(wù)管理通過(guò)”回滾規(guī)則”提供了這樣的能力(不需要調(diào)用一個(gè)特定于框架的setRollbackOnly()方法)。
遠(yuǎn)程調(diào)用 遠(yuǎn)程調(diào)用也是EJB(尤其是SLSB)證實(shí)自身價(jià)值的領(lǐng)域。EJB2.0, SLSB只能提供RMI遠(yuǎn)程調(diào)用;EJB2.1增加了Web Service遠(yuǎn)程調(diào)用。 然而,很多人認(rèn)為EJB規(guī)范混淆了遠(yuǎn)程和組件模型。很多時(shí)候,我們根本不需要遠(yuǎn)程調(diào)用。EJB極大地簡(jiǎn)化了遠(yuǎn)程調(diào)用,也使它成為一種危險(xiǎn)的誘惑---誘惑人們采用一種并不實(shí)用,而且可能非常昂貴的體系結(jié)構(gòu)(昂貴在復(fù)雜性,工作量和性能上)。 在Web應(yīng)用中,將web組件和業(yè)務(wù)組件放在同一個(gè)JVM中幾乎總是一個(gè)更好的主意。在這類應(yīng)用中使用帶遠(yuǎn)程接口的EJB無(wú)法增加任何價(jià)值,通常對(duì)于設(shè)計(jì)還是有害的。
|
聯(lián)系客服