EJB(2.X-3.0)、Hibernate、Spring:剖析、批判和展望
12/28/2004于珞珈山
一、 前言
我強(qiáng)調(diào)EJB、Hibernate、Spring的恩怨情仇,同時(shí)也必須說(shuō)明,我一向反感你說(shuō)我怎么侵入、你說(shuō)我怎么依賴式的EJB VS Hibernate、EJB VS Spring的討論,因?yàn)檫@種行為本身就是沒(méi)有意義的、錯(cuò)誤的。我提倡從正確的技術(shù)對(duì)比和理性的技術(shù)批判中受益。對(duì)比,我們需要找準(zhǔn)對(duì)比點(diǎn);批判,我們需要從source、spec、application context中分析、批判。
二、 從EJB說(shuō)起
2.1 EJB幾種Bean類型的引入順序
EJB1.0,有兩種Bean類型:SessionBean、EntityBean。
EJB2.0,引入CMP EntityBean、引入Message-Driven Bean、引入Local接口。
2.2 Entity Bean和O/R Mapping的微妙關(guān)系
我想對(duì)O/R Mapping、O/R Mapping Engine做一個(gè)簡(jiǎn)要的說(shuō)明。
O/R Mapping,以對(duì)象視圖(Object View)來(lái)看待DB Record,對(duì)象操作能夠通明地映射成DB Record操作。
O/R Mapping Engine,就是使得O/R Mapping成為可能的具體實(shí)現(xiàn)手法。
從我們的定義來(lái)看,使用BMP EntityBean意味著你自己在實(shí)施一個(gè)非常簡(jiǎn)單的O/R Mapping ,你自己在為能夠以對(duì)象視圖和DB交互做出努力。而為了支持CMP EntityBean,EJB Server提供商會(huì)為你提供O/R Mapping 能力。而且,事實(shí)的確是這樣,任何支持CMP EntityBean的EJB Server都需要提供一個(gè)Persistence(O/R Mapping) Engine,譬如JBOSS的JAWS(Just Another Web Store)。
至于,Hibernate、IBATIS等,雖然,也叫做O/R Mapping Tool,但是它們的意義已經(jīng)遠(yuǎn)遠(yuǎn)超過(guò)了CMP EntityBean O/R Mapping Engine這樣的Tool。下面會(huì)有詳細(xì)的分析。
2.3 EJB-1.0
EJB1.0是分布式組件架構(gòu),包括SessionBean和EntityBean。它引入了很多非常前衛(wèi)的技術(shù)、概念。主要包括分布式組件、容器、DB操作的對(duì)象試圖。
EJB1.0,可能Expert Group設(shè)想的EJB的應(yīng)用場(chǎng)景是大規(guī)模分布式的系統(tǒng)。所以,SessionBean、EntityBean尚沒(méi)有引入Local接口。 client->SessionBean、client->EntityBean、SessionBean->SessionBean、SessionBean->EntityBean等等都是remote的。
EJB1.0,將容器這個(gè)概念引入EJB,意義重大。這里我想順便澄清一個(gè)問(wèn)題:容器是什么?我的觀點(diǎn):容器只是一個(gè)概念、一種架構(gòu)。就拿EJB Server來(lái)說(shuō),Server試圖為Bean提供分布式、事務(wù)、安全等基礎(chǔ)設(shè)施,那么就必須有一個(gè)凌駕于Bean之上的Layer或者說(shuō)warp,這樣才能夠從高層攔截Bean調(diào)用,進(jìn)行一些額外操作。這樣的架構(gòu)就叫做容器架構(gòu),這個(gè)概念當(dāng)然不是自EJB才有的。至于怎樣實(shí)現(xiàn),方法各異。
EJB1.0為DB操作提供了對(duì)象試圖。Expert Group當(dāng)初是怎樣定位EntityBean的?無(wú)疑,1.0中的EntityBean,也就是2.0以后的BMP EntityBean,定位是Domain Object(我不知道當(dāng)時(shí)有沒(méi)有這個(gè)概念,只是它們的思想是非常一致)。它的fields直接映射DB Table Schema,member functions就是對(duì)Table Record的操作。Client->EntityBean、SessionBean->EntityBean等就可以直接和數(shù)據(jù)庫(kù)交互了。
有人跟我說(shuō)EJB1.0基于Catalysis方法學(xué),SessionBean對(duì)應(yīng)Role,EntityBean對(duì)應(yīng)Domain Object。到目前為止,我對(duì)這種說(shuō)法,持保留態(tài)度,因?yàn)?/span>EJB Spec中,我絲毫沒(méi)有這種說(shuō)法的痕跡。
2.4 EJB-2.X
無(wú)疑,EJB1.X的設(shè)計(jì)存在重大的缺陷。2.0增加的特性包括Local接口、CMP EntityBean,它們是對(duì)1.x缺陷的重大更正。
首先,事實(shí)上沒(méi)有多少Expert Group想象中的大規(guī)模分布式應(yīng)用。我們從兩個(gè)方面來(lái)說(shuō):(1)通過(guò)Remote方式使用 EntityBean引起嚴(yán)重的性能問(wèn)題,很有必要提供Local接口。(2)訪問(wèn)SessionBean的WebApplication和SessionBean部署在同一服務(wù)器上的情況非常普遍,所以提供SessionBean的Local接口,也是必然的事情。2.X之后,最常用的一個(gè)Pattern就是使用SessionBean Façade通過(guò)Local的形式訪問(wèn)EntityBean。而且,即使應(yīng)用規(guī)模大到連SessionBean和EntityBean都需要部署到不同的Server,也沒(méi)有關(guān)系,因?yàn)?/span>EJB2.X同樣支持Remote接口。
其次,EJB2.0引入CMP EntityBean。CMP EntityBean解決了EntityBean持久化表示和JDBC分離的問(wèn)題,同時(shí)大大簡(jiǎn)化了EntityBean的開(kāi)發(fā)、提高了性能。但是,我不得不說(shuō),CMP EntityBean將EJB1.X的Domain Model理念完全沖掉了,因?yàn)?/span>CMP EntityBean是不能包含任何Domain Logic的。BMP EntityBean似乎就是Matrin所說(shuō)的DomainObject,而CMP EntityBean在典型的SessionBean->EntityBean這樣的應(yīng)用場(chǎng)景下,似乎就是Martin所說(shuō)的Transaction Script中的AnaemicDomainObject。
三、 我理解的Hibernate
本來(lái),本文的題目叫做《EJB、Spring:剖析、批判和展望》,因?yàn)槲矣X(jué)的Hibernate和EJB、Spring不是一個(gè)層次的東西,雖然,這個(gè)道理很淺顯,但是為什么那么多人還拿Hibernate來(lái)攻擊EJB,來(lái)攻擊EntityBean?EntityBean是值得狠狠攻擊的,但是你用錯(cuò)了槍。
我上面提到,支持CMP EntityBean的EJB Implements都有一個(gè)Persistence Engine,也就是O/R Mapping Engine。CMP O/R Mapping Engine用來(lái)做什么的?它通過(guò)分析CMP Abastract Schema、分析EJBQL、分析Bean狀態(tài)等行為,生成SQL,然后和DB 進(jìn)行交互。
而在我眼里,Hibernate不是”O/R Mapping Tool”這幾個(gè)字能概括的了。我說(shuō)Hibernate是一款獨(dú)當(dāng)一面的輕量級(jí)翻譯中間件,是Layer,和CMP EntityBean O/R Mapping Engine不是一個(gè)層次的東西了。
Application------->CMP EntityBean Operation-------->DB |
|
在這里,我建議你停下來(lái),想想EntityBean是不是應(yīng)該對(duì)應(yīng)Hibernate中的PO/POJO?舉個(gè)例子,你修改PO后,有時(shí)是不是需要sessionObj.update(po)來(lái)更新(當(dāng)然,在非夸Session的情況下,不需要顯式的update的),這個(gè)sessionObj.update(po)是不是表示你直接使用Hibernate的Persitence Engine?是的。而在EntityBean中,你修改EntityBean后,你需要其它的行為來(lái)使得EntityBean的變化同步到DB嗎?不需要。因?yàn)椋?/span>EJB Container攔截你的調(diào)用,在你更改Bean的field之前、之后,container會(huì)調(diào)用load/store方法的(當(dāng)然,在BMP/CMP EntityBean中,情況是不同的,BMP EntityBean調(diào)用programmer自己用JDBC編寫(xiě)的load/store等方法,而CMP EntityBean,使用CMP Peristence Engine來(lái)做這個(gè)工作)。這樣,就隱式的持久化數(shù)據(jù)了。不需要,你像Hibernate那樣調(diào)用session.update這樣的語(yǔ)句。EntityBean這種同步方式是對(duì)它性能差的重要原因之一。值得注意的是,EJB Implements對(duì)于EntityBean同步并不完全是我上面描述的那樣,同步的頻率和事務(wù)、特定的implements是緊密相關(guān)的。
|
總的來(lái)說(shuō),CMP EntityBean O/R Mapping Engine是為靜態(tài)的、功能固定的EntityBean的O/R Mapping提供支持而開(kāi)發(fā)的。而Hibernate擔(dān)任的是一個(gè)Layer的作用。
四、 Spring不是神話
Rd Johnson聰明在哪里?聰明在,他堅(jiān)持了自己的實(shí)踐,而不是隨大流。Rd Johnson認(rèn)識(shí)到90%的應(yīng)用不需要分布式、不需要J2EE中那些重量級(jí)的技術(shù),譬如JNDI,他就動(dòng)手為EJB脫去Remote這層皮、將大多數(shù)應(yīng)用中不必要的技術(shù)隔離、改造。從適用范圍上來(lái)說(shuō),Spring對(duì)EJB做了90%的補(bǔ)充。
個(gè)人看法:Spring的哲學(xué)在于,framework針對(duì)最常見(jiàn)、最簡(jiǎn)單的應(yīng)用場(chǎng)景而設(shè)計(jì),等到需要特殊技術(shù)的時(shí)候,再想辦法解決問(wèn)題。這樣,在絕大多數(shù)沒(méi)有特殊要求的應(yīng)用中,Spring就顯示出優(yōu)勢(shì)來(lái)了。下面,我們會(huì)做詳細(xì)的講解。
4.1 Spring“無(wú)侵入性“是謊言,但是有資格笑”百步之外的EJB”
“無(wú)侵入性”是Spring標(biāo)榜的特性。但是,我想說(shuō),Spring的“無(wú)侵入”是謊言,隨著應(yīng)用的深入,“無(wú)侵入”對(duì)什么framework來(lái)說(shuō),都是個(gè)神化。
什么就叫“無(wú)侵入性”?部署到Spring中的Object不需要強(qiáng)制任何實(shí)現(xiàn)接口就可以說(shuō)Spring是“無(wú)侵入性”的?我覺(jué)的,這是大錯(cuò)特錯(cuò)。如果你非要說(shuō),Spring的確不需要像EJB那樣強(qiáng)制實(shí)現(xiàn)一些接口,那么我只能告訴你:
(1)Spring設(shè)想的Object的應(yīng)用場(chǎng)景是從最簡(jiǎn)單的出發(fā)。所以,它沒(méi)有,為了一些預(yù)料中要使用的特性而強(qiáng)制Object實(shí)現(xiàn)一些特定的接口。但是,事實(shí)上,在Spring中,如果你的應(yīng)用場(chǎng)景稍微深入一點(diǎn),那么你就和和Spring綁定了。
(2)Spring管理的Object,從某種意義上說(shuō)是沒(méi)有狀態(tài)的。
針對(duì)第一點(diǎn),我舉兩個(gè)個(gè)例子。(1)EJB內(nèi)部方法的調(diào)用,會(huì)導(dǎo)致基礎(chǔ)設(shè)施不會(huì)起作用。但是Bean接口(SessionBean、EntityBean、MessageDrivenBean)中都有可以使Bean獲得自己Context的支持,譬如:SessionBean的setSessionContext(SessionContext ctx) 等等,容器部署B(yǎng)ean的時(shí)候會(huì)通過(guò)它給每個(gè)Bean設(shè)置一個(gè)上下文。而EJBContext中,有EJBObject getEJBObject這樣的函數(shù),可以使得Bean獲得自身的EJBObject,這樣通過(guò)EJBObject來(lái)調(diào)用Bean自己的函數(shù),基礎(chǔ)設(shè)施就會(huì)起作用了。而Spring中,如果,一個(gè)Object的函數(shù)需要調(diào)用自己的其它函數(shù),而又希望譬如安全檢查、事務(wù)等等Aspect起作用?那么Spring,怎么做?你需要設(shè)置Bean的exposeProxy屬性。
ExposeProxy: whether the current proxy should be exposed in a ThreadLocal so that it can be accessed by the target. (It‘s available via the MethodInvocation without the need for a ThreadLocal.) If a target needs to obtain the proxy and exposeProxy is true, the target can use the AopContext.currentProxy() method.
|
所以,當(dāng)你需要上面說(shuō)的內(nèi)部調(diào)用需要基礎(chǔ)設(shè)施起作用的特性,不管在EJB還是Spring肯定需要和特定框架綁定的。為什么說(shuō),Spring五十步笑百步?因?yàn)?,我上面提到?/span>Spring在Object很簡(jiǎn)單的情況下,是可以任意部署的、復(fù)用的。而EJB卻不管你需不需要,開(kāi)始就設(shè)想你需要的。同樣,Spring中的BeanFactoryAware、BeanNameAware等等接口也都說(shuō)明了一點(diǎn):Spring將特性從Object剝離,從而,盡量降低它的依賴性。只有當(dāng)你的Object復(fù)雜的時(shí)候,framework才會(huì)侵入你的Object。
針對(duì),第二點(diǎn),我想著重談一下。為什么說(shuō),從某種意義上說(shuō)Spring中部署的對(duì)象是沒(méi)有狀態(tài)的?我們知道,Spring支持兩種Object:Singleton和Prototype。Spring Spec中,認(rèn)為,Singleton可以稱為stateless的,Prototype可以稱為是statefule的。而在EJB的世界中,StatefuleSessionBean和EntityBean也稱作是stateful的。那么,它們的stateful分別意味著什么?它們?yōu)槭裁丛谝蕾囆苑矫嬗心敲创蟮膮^(qū)別?為什么Spring中的Object不需要實(shí)現(xiàn)特定接口,而EJB需要?先來(lái),看看EJB的SessionBean接口:
|
|
|
|
|
|
|
|
其中的setSessionContext我上面說(shuō)過(guò)???/span>ejbActivate()、ejbPassive(),為什么會(huì)有這兩個(gè)函數(shù)?而Spring不需要實(shí)現(xiàn)有同樣函數(shù)的接口?這是EJB和Spring的對(duì)象管理機(jī)制的不同造成。EJB implements一般來(lái)說(shuō),為了復(fù)用Bean,會(huì)采用一級(jí)Cache加上一級(jí)InstancePool(StatelessSessionBean是不需要Cache的),從而支持將StatefulSessionBean持久化到磁盤,支持EntityBean的Bean Instance(注意這個(gè)Bean Instance和client得到的EntityBean是不同的,它沒(méi)有和任何的DB Record關(guān)聯(lián))的復(fù)用,這就導(dǎo)致了ejbAcrivate、ejbPassivate等的引入。但是,Spring沒(méi)有采用這樣管理機(jī)制,它只有Singleton/Prototype。而Prototype雖然也可以說(shuō)成是Statefule的,但是它不會(huì)在不同的client中復(fù)用Object Instance,而是每一個(gè)client一個(gè)對(duì)象,哪怕一萬(wàn)個(gè)client,那么就產(chǎn)生一萬(wàn)個(gè)Instance,而在EJB中,可能使用100 Instance來(lái)服務(wù),將not active的Bean持久化到磁盤,復(fù)用Bean Instance。還請(qǐng)注意,這里我不是說(shuō)EJB中的StatefuleSessionBean好,事實(shí)上我發(fā)現(xiàn),一般來(lái)說(shuō),當(dāng)并發(fā)量很大時(shí),采用節(jié)約內(nèi)存而持久化Bean到磁盤這種策略,I/O瓶頸引起的問(wèn)題更為嚴(yán)重。
再看,ejbRemove,這個(gè)沒(méi)什么多說(shuō)的,Spring中你可以選擇實(shí)現(xiàn)InitializingBean、DisposableBean接口,但是Spring推薦不要這樣做,可以寫(xiě)普通的init成員函數(shù),然后在配置文件中指明init-method、destroy-method屬性,這樣避免和Spring框架的綁定。
總的來(lái)說(shuō),Spring從對(duì)象最基本的引用場(chǎng)景出發(fā),當(dāng)需要復(fù)雜特性的時(shí)候,才會(huì)采用特殊機(jī)制來(lái)解決問(wèn)題,也就是在這時(shí),才會(huì)使應(yīng)用綁定到Spring中。所以,它的侵入性比較低,但是不是“無(wú)侵入性”,不是你想的那么美好,當(dāng)然,也沒(méi)有“絕對(duì)無(wú)侵入“的framework。
4.2 我覺(jué)的Spring IOC的設(shè)計(jì)思路不夠完美
Spring的IOC被一些人當(dāng)作多么神奇的東西。
EJB具有Spring中所說(shuō)的那種IOC的能力嗎?答案是肯定的。EJB中的EJB引用、資源引用、環(huán)境屬性都可以說(shuō)是IOC,不是嗎?然而,Spring和EJB的IOC不同在哪里?
Spring注入的特色:主要考慮Local Object的查找,這個(gè)時(shí)候不需要任何的協(xié)議(譬如JNDI),當(dāng)你需要注入Remote Object的時(shí)候,采用RMI協(xié)議或者使用第三方Tool(譬如Hessian)。
EJB的特色:無(wú)論你的Bean-Bean是否部署在同一臺(tái)機(jī)器上、Client->Bean是否在同一臺(tái)機(jī)器上,肯定需要通過(guò)JNDI來(lái)查詢Bean,只是,如果是它們?cè)谕慌_(tái)機(jī)器上的時(shí)候,你使用Local接口,這樣使得調(diào)用變?yōu)?/span>Local調(diào)用,從而提升性能。EJB它從出生時(shí)起,就定位為分布式組件架構(gòu),一頭栽進(jìn)“distributed”不容易出來(lái)了。這個(gè)可能就叫“尾大不掉”吧。
這一切的不同,只能說(shuō),它們的定位不同。一個(gè)更關(guān)注Local、一個(gè)更關(guān)注Remote。Spring仍然堅(jiān)持它的哲學(xué),從最基本的、大多數(shù)的場(chǎng)景考慮起,到特殊需要的時(shí)候,再想辦法來(lái)解決問(wèn)題。它試圖找到J2EE開(kāi)發(fā)和系統(tǒng)能力的均衡點(diǎn)。
可以說(shuō),Spring的做法,更加合情合理。但是,我也相信,Spring在”只是為Remote注入提供簡(jiǎn)單的支持“這一點(diǎn)上有點(diǎn)矯枉過(guò)正。我覺(jué)的,它可以做的更好,譬如通過(guò)作為J2EE標(biāo)準(zhǔn)的JNDI來(lái)封裝Local、Remote查找。
目前,Spring不怎么關(guān)心Remote Object注入,對(duì)于需要Remote注入的情況,只提供簡(jiǎn)單的支持,而且還需要針對(duì)expert單獨(dú)寫(xiě)配置信息。在這里,EJB3.0的做法,我覺(jué)的,是目前,最方便、最理智、也是最有前途的。EJB3.0通過(guò)@remote、@local就可以讓EJB Server做不同的部署。
Spring導(dǎo)出遠(yuǎn)程對(duì)象。
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- does not necessarily have to be the same name as the bean to be exported -->
<property name="serviceName"><value>AccountService</value></property>
<property name="service"><ref bean="accountService"/></property>
<property name="serviceInterface"><value>example.AccountService</value></property>
<!-- defaults to 1099 -->
<property name="registryPort"><value>1199</value></property>
</bean>
Spring中注入Remote是怎樣做的?
<bean class="example.SimpleObject">
<property name="accountService"><ref bean="accountService"/></bean>
</bean>
<bean id="accountService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl"><value>rmi://HOST:1199/AccountService</value></property>
<property name="serviceInterface"><value>example.AccountService</value></property>
</bean>
看了,這段代碼,你就知道了。
這種方法非常的輕量級(jí),從本質(zhì)上來(lái)說(shuō),這種方法和JNDI沒(méi)有任何的不同,這種方法,也需要一個(gè)NamingService,還記得RMI編程中,運(yùn)行服務(wù)端的時(shí)候,首先運(yùn)行rmiregistry,這個(gè)實(shí)際上就是非常簡(jiǎn)單的NamingService。看來(lái),Rd Johnson對(duì)JNDI真是深惡痛絕啊。怎么也不愿意用JNDI。Spring這種方法,也許沒(méi)有JNDI那樣重量級(jí),但是很顯然它不能支持工業(yè)級(jí)分布系統(tǒng),J2EE發(fā)展到今天,JNDI已經(jīng)成為最核心的技術(shù),它不是簡(jiǎn)單的Object Naming Service,它提供標(biāo)準(zhǔn)接口來(lái)定位用戶、微機(jī)、網(wǎng)絡(luò)、對(duì)象、服務(wù)器等等。它已經(jīng)廣泛而深入的進(jìn)入J2EE技術(shù)的各個(gè)領(lǐng)域、成為J2EE系統(tǒng)的紐帶。
舉個(gè)很簡(jiǎn)單的例子:我需要在Spring應(yīng)用中動(dòng)態(tài)獲取Remote Object,我該怎么做?我需要無(wú)縫使用LDAP,我該怎么做?答案是,Spring不能幫到你什么。
那么我就想,Spring為什么不使用JNDI來(lái)封裝Local、Remote查找兩種協(xié)議?從而,使用J2EE標(biāo)準(zhǔn)來(lái)實(shí)現(xiàn)無(wú)縫“注入”。這樣帶來(lái)的優(yōu)點(diǎn)就是:(1)適應(yīng)JNDI已經(jīng)廣泛而深入滲透的領(lǐng)域(2)JNDI是J2EE標(biāo)準(zhǔn)(3)支持動(dòng)態(tài)Remote Service獲取(4)支持工業(yè)級(jí)分布系統(tǒng)。
Properties props = new Properties();
pros.put(“searchServiceFactory”,”org.net.spring.bean.BeanFactory”);
Context ctx = new Context(env);
ctx.lookup(“servicename”);
Properties props = new Properties();
pros.put(“searchServiceFactory”,”com.sun.j2ee.jndi”);
Context ctx = new Context(env);
ctx.lookup(“servicename”); |
從下面,你可以看出,我個(gè)人認(rèn)為Spring如果仍能OS,free,也許還會(huì)有很多人選擇它,但是如果,它試圖商業(yè)化,那么可以肯定它必須向EJB3.0靠攏。向標(biāo)準(zhǔn)靠攏。
|
4.3 獨(dú)立的、完整的、面向Programmers的AOP框架才是Spring真正的亮點(diǎn)
EJB具有Spring中所宣揚(yáng)的AOP能力嗎?答案是肯定的。EJB的基礎(chǔ)設(shè)施就是使用AOP技術(shù)實(shí)現(xiàn)的。然而,我要說(shuō),EJB的AOP并沒(méi)有面向Programmers。為什么這么說(shuō)?EJB Implements為你提供一組基礎(chǔ)設(shè)施(例如,JBOSS中那些可配置的interceptors)。你可以根據(jù)系統(tǒng)需要配置。但是,你不可以編寫(xiě)自己的interceptor,然后配置到系統(tǒng)中。因?yàn)?/span>EJB的interceptors往往和EJB Implements內(nèi)部愈合很緊,你想編寫(xiě)自己的interceptor,意味著你必須閱讀EJB Implements的source,了解它的實(shí)現(xiàn)。換句話說(shuō),EJB Implements中的AOP技術(shù)是為了EJB Server能夠提供基礎(chǔ)設(shè)施而使用的,它沒(méi)有想到為programmer提供更多的AOP能力。而Spring的AOP開(kāi)始就是作為一個(gè)框架來(lái)發(fā)展的,是獨(dú)立的、完整的。造成這種情況,是歷史的原因。EJB Implements作者也不是神人,他們不可能,N年前,就想到將AOP框架設(shè)計(jì)的足夠獨(dú)立,從而面向programmes。
個(gè)人觀點(diǎn):EJB3.0在基礎(chǔ)設(shè)施方面的說(shuō)明,基本沿襲EJB2.X的。只是,可以提到EJB3.0支持通過(guò)annotations來(lái)使用基礎(chǔ)設(shè)施,沒(méi)有說(shuō),EJB3.0需要完善的AOP框架,但是,我想,EJB3.0 Implments應(yīng)該都會(huì)提供一個(gè)獨(dú)立的、完整的、面向programmer的AOP框架。事實(shí)上,JBOSS不早就有了J
|
當(dāng)然,在Spring中使用AOP也不是那么的輕松,譬如,讓你自己寫(xiě)TransactionProxy,你還是需要了解Spring AOP內(nèi)部運(yùn)作機(jī)制的。
4.4 Spring對(duì)其它框架的集成
這個(gè)問(wèn)題,就不談了。
五、EJB將走向何方
5.1 EJB-3.0
我們沒(méi)必要說(shuō)EJB2.X本身有多少的缺陷,畢竟,它是前一個(gè)J2EE時(shí)代的產(chǎn)物,只能說(shuō)EJB2.X已經(jīng)不能反映大多數(shù)J2EE應(yīng)用的實(shí)際需要。過(guò)時(shí)了。那么EJB3.0打算帶我們走向何方?
EJB3.0 Spec除了針對(duì)簡(jiǎn)化開(kāi)發(fā)、方便測(cè)試、方便部署等目標(biāo)做了不少的修改,更重要的是EJB3.0對(duì)SessionBean,特別是EntityBean模型做了一個(gè)全面的整容手術(shù)。這種修改是革命性的。
在我的《如果我來(lái)改進(jìn)EJB2.X模型》中,我談到,如果,讓我對(duì)EJB2.X的EntityBean模型做修改,那么首先需要為新的模型定好位。就拿EntityBean來(lái)說(shuō)好了。
第一條路:繼續(xù)EntityBean設(shè)計(jì)的初試?yán)砟睿?/span>Remote Domain Model(包括BMP EntityBean代表的Domain Model和CMP EntityBean代表的AnaemicDomainObject),并且保留Local接口,力圖改經(jīng)持久模型的設(shè)計(jì),提高性能(即使CMP EntityBean的性能也是難以令人接受的,這種情況,我個(gè)人認(rèn)為,主要是因?yàn)?/span>EntityBean模型設(shè)計(jì)的不好,在我的另一篇《如果我來(lái)改進(jìn)EJB2.X模型》中有深入的分析)、增強(qiáng)功能(EJBQL實(shí)在太弱),讓那些連SessionBean、EntityBean都需要部署在不同Server上的應(yīng)用來(lái)為EJB2.X的EntityBean留口氣。
但是,顯然,EJB Server提供商是不可能甘心這一點(diǎn)羹的,因?yàn)槟菢拥膽?yīng)用實(shí)在太少了。事實(shí)已經(jīng)證明,如果EntityBean的Remote不是必須的,那么RemoteEntityBean性能上是不可行的,它只能工作在SessionBean后端,然而,即使EntityBean工作在SessionBean后端,但是EntityBean本身的局限性也太多,粒度要么太粗要么太細(xì),性能、功能太弱,等等,開(kāi)發(fā)數(shù)據(jù)應(yīng)用非常地蹩腳,那么如果,在Remote EntityBean不是必須的情況下,我為什么不完全放棄EntityBean,在SessionBean后端使用其它的O/R Mapping Tool來(lái)開(kāi)發(fā)數(shù)據(jù)應(yīng)用,譬如Hibernate。這就是,EntityBean可以走第二條路。當(dāng)然,從某種意義上來(lái)說(shuō),也是它必須走的路。
第二條路:完全拋棄EntityBean,采用Hibernate這樣的O/R Mapping Engine作為Session Bean、Message-Driven Bean的后端數(shù)據(jù)持久化工具。而從EJB3.0可以看出,EJB3.0的確完全拋棄了傳統(tǒng)的EntityBean模型。個(gè)人意見(jiàn):可以這樣說(shuō)吧,EntityBean已經(jīng)不復(fù)存在,Expert Group在SessionBean下給你換上了一個(gè)非常sharp的Persistence engine,你拿著engine,想干什么就干什么好了(上面講過(guò),EntityBean中,PersitenceEngine對(duì)client是通明的,這是由這兩種引擎的本質(zhì)作用決定的。有人說(shuō),EntityBean Application中不可以使用Dynamic Query,只能在配置文件中申明EJBQL,這些都是兩種Persistence Engine的本質(zhì)所決定的)。蹩腳的、強(qiáng)制模型的EntityBean不復(fù)存在!另外,EntityBean Remote特性在EJB3.0中根本沒(méi)有提到,或許只是作為一個(gè)可選特性了吧(我還沒(méi)有想到,EJB3.0中,如何來(lái)支持Remote PO,這個(gè)問(wèn)題很詭異)。看來(lái),Expert Group已經(jīng)徹底否定了EntityBean的設(shè)計(jì),或者說(shuō)EntityBean的確是不符合實(shí)際需求的,Remote EntityBean、Remote Domain Object在絕大多數(shù)情況下是不切實(shí)際的。
話外題:Hibernate和JDO的關(guān)系,很微妙。EJB3.0和JDO的合并、Gavin進(jìn)入EJB3.0 ExpertGroup令人很迷惑。EJB3.0的持久化模型采用JDO,應(yīng)該是理所當(dāng)然的。但是,目前,EJB3.0的Persitence Engine部分似乎被Hibernate左右,那么JDO的位置應(yīng)該在哪里?
|
六、Spring將走向何方
無(wú)疑,“聽(tīng)起來(lái)很美妙的”IOC、實(shí)力、實(shí)用派Spring AOP、集成大量framework的Spring是目前、對(duì)分布式、高級(jí)J2EE特性要求不強(qiáng)的系統(tǒng)的最合理選擇。但是,你可以看到,Spring能做到的,除了集成大量framework這個(gè)特性外(當(dāng)然這個(gè)永遠(yuǎn)不會(huì)被寫(xiě)進(jìn)EJB Spec,但是如果EJB Server供應(yīng)商想這樣做,也是非常簡(jiǎn)單的事),EJB3.0也能做到,而且很多地方做的比Spring好很多,最重要的,EJB是標(biāo)準(zhǔn),所以,很肯定的說(shuō),如果Spring OS、free,保持目前的姿態(tài)發(fā)展,仍然會(huì)成為開(kāi)發(fā)人員不錯(cuò)的選擇,然而,如果Spring試圖商業(yè)化,我是Rd Johnson的話,我會(huì)向EJB3.0靠攏,搖身成為EJB3.0 Server提供商。
七、EJB3.0是J2EE商用framework的未來(lái)
大肆革新過(guò)的EJB3.0,是J2EE商用framework的將來(lái)。
|
來(lái)自: figol > 《面向?qū)ο笤O(shè)計(jì)》