EJB(2.X-3.0),Hibernate,Spring剖析,批判和展望

 一段時間以來,EJBHibernateSpring的恩怨情仇,是J2EE的熱門話題。EJB VS HibernateEJB VS Spring
樣的議題隨處可在。這篇文章,筆者試圖通過對技術發展史的回顧,對
source的剖析、對比,深入挖掘這些技術出現的初衷、缺陷、走向。

一、    前言

 我強調EJBHibernateSpring的恩怨情仇,同時也必須說明,我一向反感你說我怎麼侵入、你說我怎麼依賴式的EJB VS HibernateEJB VS Spring的討論,因爲這種行爲本身就是沒有意義的、錯誤的。我提倡從正確的技術對比和理性的技術批判中受益。對比,我們需要找準對比點;批判,我們需要從sourcespecapplication context中分析、批判。

 

二、    EJB說起

2.1 EJB幾種Bean類型的引入順序

 EJB1.0,有兩種Bean類型:SessionBeanEntityBean

 EJB2.0,引入CMP EntityBean、引入Message-Driven Bean、引入Local接口。

 

2.2 Entity BeanO/R Mapping的微妙關係

 我想對O/R MappingO/R Mapping Engine做一個簡要的說明。

 O/R Mapping,以對象視圖(Object View)來看待DB Record,對象操作能夠通明地映射成DB Record操作。

 O/R Mapping Engine,就是使得O/R Mapping成爲可能的具體實現手法。

從我們的定義來看,使用BMP EntityBean意味着你自己在實施一個非常簡單的O/R Mapping ,你自己在爲能夠以對象視圖和DB交互做出努力。而爲了支持CMP EntityBeanEJB Server提供商會爲你提供O/R Mapping 能力。而且,事實的確是這樣,任何支持CMP EntityBeanEJB Server都需要提供一個Persistence(O/R Mapping) Engine,譬如JBOSSJAWS(Just Another Web Store)

 至於,HibernateIBATIS等,雖然,也叫做O/R Mapping Tool,但是它們的意義已經遠遠超過了CMP EntityBean O/R Mapping Engine這樣的Tool。下面會有詳細的分析。

 

2.3 EJB-1.0

 EJB1.0是分佈式組件架構,包括SessionBeanEntityBean。它引入了很多非常前衛的技術、概念。主要包括分佈式組件、容器、DB操作的對象試圖。

 EJB1.0,可能Expert Group設想的EJB的應用場景是大規模分佈式的系統。所以,SessionBeanEntityBean尚沒有引入Local接口。 client->SessionBeanclient->EntityBeanSessionBean->SessionBeanSessionBean->EntityBean等等都是remote的。

 EJB1.0,將容器這個概念引入EJB,意義重大。這裏我想順便澄清一個問題:容器是什麼?我的觀點:容器只是一個概念、一種架構。就拿EJB Server來說,Server試圖爲Bean提供分佈式、事務、安全等基礎設施,那麼就必須有一個凌駕於Bean之上的Layer或者說warp,這樣才能夠從高層攔截Bean調用,進行一些額外操作。這樣的架構就叫做容器架構,這個概念當然不是自EJB纔有的。至於怎樣實現,方法各異。

 

事實上,以個人的觀點,容器架構的核心,不在於從高層“掌握”Beans(Objects),而在於採用怎樣的技術來實現Bean(Object)調用的攔截。無疑,EJB ServersSpring的實現手法是不同的。下面會詳細討論這個問題。

 

 EJB1.0DB操作提供了對象試圖。Expert Group當初是怎樣定位EntityBean的?無疑,1.0中的EntityBean,也就是2.0以後的BMP EntityBean,定位是Domain Object(我不知道當時有沒有這個概念,只是它們的思想是非常一致)。它的fields直接映射DB Table Schemamember functions就是對Table Record的操作。Client->EntityBeanSessionBean->EntityBean等就可以直接和數據庫交互了。

 有人跟我說EJB1.0基於Catalysis方法學,SessionBean對應RoleEntityBean對應Domain Object。到目前爲止,我對這種說法,持保留態度,因爲EJB Spec中,我絲毫沒有這種說法的痕跡。

 

2.4 EJB-2.X

 無疑,EJB1.X的設計存在重大的缺陷。2.0增加的特性包括Local接口、CMP EntityBean,它們是對1.x缺陷的重大更正。

 首先,事實上沒有多少Expert Group想象中的大規模分佈式應用。我們從兩個方面來說:(1)通過Remote方式使用 EntityBean引起嚴重的性能問題,很有必要提供Local接口。(2)訪問SessionBeanWebApplicationSessionBean部署在同一服務器上的情況非常普遍,所以提供SessionBeanLocal接口,也是必然的事情。2.X之後,最常用的一個Pattern就是使用SessionBean Façade通過Local的形式訪問EntityBean。而且,即使應用規模大到連SessionBeanEntityBean都需要部署到不同的Server,也沒有關係,因爲EJB2.X同樣支持Remote接口。

 其次,EJB2.0引入CMP EntityBeanCMP EntityBean解決了EntityBean持久化表示和JDBC分離的問題,同時大大簡化了EntityBean的開發、提高了性能。但是,我不得不說,CMP EntityBeanEJB1.XDomain Model理念完全沖掉了,因爲CMP EntityBean是不能包含任何Domain Logic的。BMP EntityBean似乎就是Matrin所說的DomainObject,而CMP EntityBean在典型的SessionBean->EntityBean這樣的應用場景下,似乎就是Martin所說的Transaction Script中的AnaemicDomainObject

順便說一下,我個人是不同意MartinRichDomainObject的說法。因爲,在數據應用系統中Martin提到的相對於Transacton ScriptAnaemicDomainObjectRichDomainModel往往沒有反映現實世界。一個Bank Account反映到現實世界,就是賬本中的一條記錄,它沒有自發的動作,譬如withdraw。它和Person不同,Person可以有say(String words)這樣的自發動作。Accountwithdraw應該放到AccountManager中,由AccountManger來操作Account。不是說OO中的Object都需要有動作,現實世界中,本來就有靜態的、沒有自發動作的事物,譬如一個賬本、一個帳號、一個資料庫。雖然,不可否認,Rich Domain Model(對比AnaemicDomainObject說的)能夠帶來不少的好處(什麼樣的好處,你看看Martin《Domain Logic and SQL》,就知道了)

 

三、    我理解的Hibernate

 本來,本文的題目叫做《EJBSpring:剖析、批判和展望》,因爲我覺的HibernateEJBSpring不是一個層次的東西,雖然,這個道理很淺顯,但是爲什麼那麼多人還拿Hibernate來攻擊EJB,來攻擊EntityBeanEntityBean是值得狠狠攻擊的,但是你用錯了槍。

 我上面提到,支持CMP EntityBeanEJB Implements都有一個Persistence Engine,也就是O/R Mapping EngineCMP O/R Mapping Engine用來做什麼的?它通過分析CMP Abastract Schema、分析EJBQL、分析Bean狀態等行爲,生成SQL,然後和DB 進行交互。

而在我眼裏,Hibernate不是”O/R Mapping Tool”這幾個字能概括的了。我說Hibernate是一款獨當一面的輕量級翻譯中間件,是Layer,和CMP EntityBean O/R Mapping Engine不是一個層次的東西了。

Application------->CMP EntityBean Operation-------->DB

                                      |
                                
 (O/R Mapping Engine)


 

                                                           |---HQLCriteria Query

Application------> Hibernate ------> |---POJO/PO Operation---------> DB

                                                           |---and so on

 通過上面的兩個圖,你看出區別來了嗎?

 EntityBean應用,不知道O/R Mapping Engine的存在,只需要使用EntityBean來完成交互。

 而在Hibernate應用中,Application是直接使用Hibernate的。也就是說,它是直接使用O/R Mapping Engine的。

 在這裏,我建議你停下來,想想EntityBean是不是應該對應Hibernate中的PO/POJO?舉個例子,你修改PO後,是不是需要sessionObj.update(po)來更新,這個sessionObj.update(po)是不是表示你直接使用HibernatePersitence Engine?是的。而在EntityBean中,你修改EntityBean後,你需要其它的行爲來使得EntityBean的變化同步到DB嗎?不需要。因爲,EJB Container攔截你的調用,在你更改Beanfield之前、之後,container會調用load/store方法的(當然,在BMP/CMP EntityBean中,情況是不同的,BMP EntityBean調用programmer自己用JDBC編寫的load/store等方法,而CMP EntityBean,使用CMP Peristence Engine來做這個工作)。這樣,就隱式的持久化數據了。不需要,你像Hibernate那樣調用session.update這樣的語句。EntityBean這種同步方式是對它性能差的重要原因之一。值得注意的是,EJB Implements對於EntityBean同步並不完全是我上面描述的那樣,同步的頻率和事務、特定的implements是緊密相關的。

 總的來說,CMP EntityBean O/R Mapping Engine是爲靜態的、功能固定的EntityBeanO/R Mapping提供支持而開發的。而Hibernate擔任的是一個Layer的作用。

 

四、    Spring不是神話

 Rd Johnson聰明在哪裏?聰明在,他堅持了自己的實踐,而不是隨大流。Rd Johnson認識到90%的應用不需要分佈式、不需要J2EE中那些重量級的技術,譬如JNDI,他就動手爲EJB脫去Remote這層皮、將大多數應用中不必要的技術隔離、改造。從適用範圍上來說,SpringEJB做了90%的補充。

 個人看法:Spring的哲學在於,framework針對最常見、最簡單的應用場景而設計,等到需要特殊技術的時候,再想辦法解決問題。這樣,在絕大多數沒有特殊要求的應用中,Spring就顯示出優勢來了。下面,我們會做詳細的講解。

 

4.1 Spring“無侵入性“是謊言,但是有資格笑”百步之外的EJB”

 “無侵入性”是Spring標榜的特性。但是,我想說,Spring的“無侵入”是謊言,隨着應用的深入,“無侵入”對什麼framework來說,都是個神化。

 什麼就叫“無侵入性”?部署到Spring中的Object不需要強制任何實現接口就可以說Spring是“無侵入性”的?我覺的,這是大錯特錯。如果你非要說,Spring的確不需要像EJB那樣強制實現一些接口,那麼我只能告訴你:

(1)Spring設想的Object的應用場景是從最簡單的出發。所以,它沒有,爲了一些預料中要使用的特性而強制Object實現一些特定的接口。但是,事實上,在Spring中,如果你的應用場景稍微深入一點,那麼你就和和Spring綁定了。

(2)Spring管理的Object,從某種意義上說是沒有狀態的。

針對第一點,我舉兩個個例子。(1)EJB內部方法的調用,會導致基礎設施不會起作用。但是Bean接口(SessionBeanEntityBeanMessageDrivenBean)中都有可以使Bean獲得自己Context的支持,譬如:SessionBean的setSessionContext(SessionContext ctx) 等等,容器部署Bean的時候會通過它給每個Bean設置一個上下文。而EJBContext中,有EJBObject getEJBObject這樣的函數,可以使得Bean獲得自身的EJBObject,這樣通過EJBObject來調用Bean自己的函數,基礎設施就會起作用了。而Spring中,如果,一個Object的函數需要調用自己的其它函數,而又希望譬如安全檢查、事務等等Aspect起作用?那麼Spring,怎麼做?你需要設置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.

所以,當你需要上面說的內部調用需要基礎設施起作用的特性,不管在EJB還是Spring肯定需要和特定框架綁定的。爲什麼說,Spring五十步笑百步?因爲,我上面提到,SpringObject很簡單的情況下,是可以任意部署的、複用的。而EJB卻不管你需不需要,開始就設想你需要的。同樣,Spring中的BeanFactoryAwareBeanNameAware等等接口也都說明了一點Spring將特性從Object剝離從而儘量降低它的依賴性。只有當你的Object複雜的時候,framework纔會侵入你的Object

 針對,第二點,我想着重談一下。爲什麼說,從某種意義上說Spring中部署的對象是沒有狀態的?我們知道,Spring支持兩種ObjectSingletonPrototypeSpring Spec中,認爲,Singleton可以稱爲stateless的,Prototype可以稱爲是statefule的。而在EJB的世界中,StatefuleSessionBeanEntityBean也稱作是stateful的。那麼,它們的stateful分別意味着什麼?它們爲什麼在依賴性方面有那麼大的區別?爲什麼Spring中的Object不需要實現特定接口,而EJB需要?先來,看看EJBSessionBean接口:

void

ejbActivate()
          The activate method is called when the instance is activated from its 
          "passive" state.

 void

ejbPassivate()
          The passivate method is called before the instance enters the
          "passive" state.

 void

ejbRemove()
          A container invokes this method before it ends the life of the 
          session object.

 void

setSessionContext(SessionContext ctx)
          Set the associated session context.

其中的setSessionContext我上面說過。看ejbActivate()ejbPassive(),爲什麼會有這兩個函數?而Spring不需要實現有同樣函數的接口?這是EJBSpring的對象管理機制的不同造成。EJB implements一般來說,爲了複用Bean,會採用一級Cache加上一級InstancePool(StatelessSessionBean是不需要Cache),從而支持將StatefulSessionBean持久化到磁盤,支持EntityBeanBean Instance(注意這個Bean Instanceclient得到的EntityBean是不同的,它沒有和任何的DB Record關聯)的複用,這就導致了ejbAcrivateejbPassivate等的引入。但是,Spring沒有采用這樣管理機制,它只有Singleton/Prototype。而Prototype雖然也可以說成是Statefule的,但是它不會在不同的client中複用Object Instance,而是每一個client一個對象,哪怕一萬個client,那麼就產生一萬個Instance,而在EJB中,可能使用100 Instance來服務,將not activeBean持久化到磁盤,複用Bean Instance。還請注意,這裏我不是說EJB中的StatefuleSessionBean好,事實上我發現,一般來說,當併發量很大時,採用節約內存而持久化Bean到磁盤這種策略,I/O瓶頸引起的問題更爲嚴重。

 再看,ejbRemove,這個沒什麼多說的,Spring中你可以選擇實現InitializingBeanDisposableBean接口但是Spring推薦不要這樣做可以寫普通的init成員函數,然後在配置文件中指明init-methoddestroy-method屬性這樣避免和Spring框架的綁定。

 總的來說,Spring從對象最基本的引用場景出發,當需要複雜特性的時候,纔會採用特殊機制來解決問題,也就是在這時,纔會使應用綁定到Spring中。所以,它的侵入性比較低,但是不是“無侵入性”,不是你想的那麼美好,當然,也沒有“絕對無侵入“的framework

 

4.2 我覺的Spring IOC的設計思路不夠完美

 SpringIOC被一些人當作多麼神奇的東西。

EJB具有Spring中所說的那種IOC的能力嗎?答案是肯定的。EJB中的EJB引用、資源引用、環境屬性都可以說是IOC,不是嗎?然而,SpringEJBIOC不同在哪裏?

Spring注入的特色:主要考慮Local Object的查找這個時候不需要任何的協議譬如JNDI),當你需要注入Remote Object的時候採用RMI協議或者使用第三方Tool(譬如Hessian

EJB的特色:無論你的Bean-Bean是否部署在同一臺機器上、Client->Bean是否在同一臺機器上,肯定需要通過JNDI來查詢Bean,只是,如果是它們在同一臺機器上的時候,你使用Local接口,這樣使得調用變爲Local調用,從而提升性能。EJB它從出生時起,就定位爲分佈式組件架構,一頭栽進distributed”不容易出來了。這個可能就叫“尾大不掉”吧。

這一切的不同,只能說,它們的定位不同。一個更關注Local、一個更關注RemoteSpring仍然堅持它的哲學,從最基本的、大多數的場景考慮起,到特殊需要的時候,再想辦法來解決問題。它試圖找到J2EE開發和系統能力的均衡點。

 可以說,Spring的做法,更加合情合理。但是,我也相信,Spring在”只是爲Remote注入提供簡單的支持“這一點上有點矯枉過正。我覺的,它可以做的更好,譬如通過作爲J2EE標準的JNDI來封裝LocalRemote查找。

目前,Spring不怎麼關心Remote Object注入,對於需要Remote注入的情況,只提供簡單的支持,而且還需要針對expert單獨寫配置信息。在這裏,EJB3.0的做法,我覺的,是目前,最方便、最理智、也是最有前途的。EJB3.0通過@remote@local就可以讓EJB Server做不同的部署。

Spring導出遠程對象。

<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>

看了,這段代碼,你就知道了。

這種方法非常的輕量級,從本質上來說,這種方法和JNDI沒有任何的不同,這種方法,也需要一個NamingService,還記得RMI編程中,運行服務端的時候,首先運行rmiregistry這個實際上就是非常簡單的NamingService。看來,Rd JohnsonJNDI真是深惡痛絕啊。怎麼也不願意用JNDISpring這種方法,也許沒有JNDI那樣重量級,但是很顯然它不能支持工業級分佈系統,J2EE發展到今天,JNDI已經成爲最核心的技術,它不是簡單的Object Naming Service,它提供標準接口來定位用戶、微機、網絡、對象、服務器等等。它已經廣泛而深入的進入J2EE技術的各個領域、成爲J2EE系統的紐帶。

舉個很簡單的例子:我需要在Spring應用中動態獲取Remote Object,我該怎麼做?我需要無縫使用LDAP,我該怎麼做?答案是,Spring不能幫到你什麼。

那麼我就想,Spring爲什麼不使用JNDI來封裝LocalRemote查找兩種協議?從而,使用J2EE標準來實現無縫“注入”。這樣帶來的優點就是:(1)適應JNDI已經廣泛而深入滲透的領域(2)JNDIJ2EE標準(3)支持動態Remote Service獲取(4)支持工業級分佈系統。

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”);

 

 

 從下面,你可以看出,我個人認爲Spring如果仍能OSfree,也許還會有很多人選擇它,但是如果,它試圖商業化,那麼可以肯定它必須向EJB3.0靠攏。向標準靠攏。

 

 

4.3 獨立的、完整的、面向ProgrammersAOP框架纔是Spring真正的亮點

 EJB具有Spring中所宣揚的AOP能力嗎?答案是肯定的。EJB的基礎設施就是使用AOP技術實現的。然而,我要說,EJBAOP並沒有面向Programmers。爲什麼這麼說?EJB Implements爲你提供一組基礎設施(例如,JBOSS中那些可配置的interceptors)。你可以根據系統需要配置。但是,你不可以編寫自己的interceptor,然後配置到系統中。因爲EJBinterceptors往往和EJB Implements內部癒合很緊,你想編寫自己的interceptor,意味着你必須閱讀EJB Implementssource,瞭解它的實現。換句話說,EJB Implements中的AOP技術是爲了EJB Server能夠提供基礎設施而使用的,它沒有想到爲programmer提供更多的AOP能力。而SpringAOP開始就是作爲一個框架來發展的,是獨立的、完整的。造成這種情況,是歷史的原因。EJB Implements作者也不是神人,他們不可能,N年前,就想到將AOP框架設計的足夠獨立,從而面向programmes

個人觀點:EJB3.0在基礎設施方面的說明,基本沿襲EJB2.X的。只是,可以提到EJB3.0支持通過annotations來使用基礎設施,沒有說,EJB3.0需要完善的AOP框架,但是,我想,EJB3.0 Implments應該都會提供一個獨立的、完整的、面向programmerAOP框架。事實上,JBOSS不早就有了J

 當然,在Spring中使用AOP也不是那麼的輕鬆,譬如,讓你自己寫TransactionProxy,你還是需要了解Spring AOP內部運作機制的。

 

4.4 Spring對其它框架的集成

 這個問題,就不談了。


五、
EJB將走向何方

5.1 EJB-3.0

 我們沒必要說EJB2.X本身有多少的缺陷,畢竟,它是前一個J2EE時代的產物,只能說EJB2.X已經不能反映大多數J2EE應用的實際需要。過時了。那麼EJB3.0打算帶我們走向何方?

 EJB3.0 Spec除了針對簡化開發、方便測試、方便部署等目標做了不少的修改,更重要的是EJB3.0SessionBean,特別是EntityBean模型做了一個全面的整容手術。這種修改是革命性的。

在我的《如果我來改進EJB2.X模型》中,我談到,如果,讓我對EJB2.XEntityBean模型做修改,那麼首先需要爲新的模型定好位。就拿EntityBean來說好了。 

第一條路:繼續EntityBean設計的初試理念:Remote Domain Model(包括BMP EntityBean代表的Domain ModelCMP EntityBean代表的AnaemicDomainObject),並且保留Local接口,力圖改經持久模型的設計,提高性能(即使CMP EntityBean的性能也是難以令人接受的,這種情況,我個人認爲,主要是因爲EntityBean模型設計的不好,在我的另一篇《如果我來改進EJB2.X模型》中有深入的分析)、增強功能(EJBQL實在太弱),讓那些連SessionBeanEntityBean都需要部署在不同Server上的應用來爲EJB2.XEntityBean留口氣。

但是,顯然,EJB Server提供商是不可能甘心這一點羹的,因爲那樣的應用實在太少了。事實已經證明,如果EntityBeanRemote不是必須的,那麼RemoteEntityBean性能上是不可行的,它只能工作在SessionBean後端,然而,即使EntityBean工作在SessionBean後端,但是EntityBean本身的侷限性也太多,粒度要麼太粗要麼太細,性能、功能太弱,等等,開發數據應用非常地蹩腳,那麼如果,在Remote EntityBean不是必須的情況下,我爲什麼不完全放棄EntityBean,在SessionBean後端使用其它的O/R Mapping Tool來開發數據應用,譬如Hibernate。這就是,EntityBean可以走第二條路。當然,從某種意義上來說,也是它必須走的路。

第二條路:完全拋棄EntityBean,採用Hibernate這樣的O/R Mapping Engine作爲Session BeanMessage-Driven Bean的後端數據持久化工具。而從EJB3.0可以看出,EJB3.0的確完全拋棄了傳統的EntityBean模型。個人意見:可以這樣說吧,EntityBean已經不復存在,Expert GroupSessionBean下給你換上了一個非常sharpPersistence engine,你拿着engine,想幹什麼就幹什麼好了(上面講過,EntityBean中,PersitenceEngineclient是通明的,這是由這兩種引擎的本質作用決定的。有人說,EntityBean Application中不可以使用Dynamic Query,只能在配置文件中申明EJBQL,這些都是兩種Persistence Engine的本質所決定的)。蹩腳的、強制模型的EntityBean不復存在!另外,EntityBean Remote特性在EJB3.0中根本沒有提到,或許只是作爲一個可選特性了吧(我還沒有想到,EJB3.0中,如何來支持Remote PO,這個問題很詭異)。看來,Expert Group已經徹底否定了EntityBean的設計,或者說EntityBean的確是不符合實際需求的,Remote EntityBeanRemote Domain Object在絕大多數情況下是不切實際的。

話外題:HibernateJDO的關係,很微妙。EJB3.0JDO的合併、Gavin進入EJB3.0 ExpertGroup令人很迷惑。EJB3.0的持久化模型採用JDO,應該是理所當然的。但是,目前,EJB3.0Persitence Engine部分似乎被Hibernate左右,那麼JDO的位置應該在哪裏?

 

六、Spring將走向何方

 無疑,“聽起來很美妙的”IOC、實力、實用派Spring AOP、集成大量frameworkSpring是目前、對分佈式、高級J2EE特性要求不強的系統的最合理選擇。但是,你可以看到,Spring能做到的,除了集成大量framework這個特性外(當然這個永遠不會被寫進EJB Spec,但是如果EJB Server供應商想這樣做,也是非常簡單的事),EJB3.0也能做到,而且很多地方做的比Spring好很多,最重要的,EJB是標準,所以,很肯定的說,如果Spring OSfree,保持目前的姿態發展,仍然會成爲開發人員不錯的選擇,然而,如果Spring試圖商業化,我是Rd Johnson的話,我會向EJB3.0靠攏,搖身成爲EJB3.0 Server提供商。

 

七、EJB3.0J2EE商用framework的未來

 大肆革新過的EJB3.0,是J2EE商用framework的將來。

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章