国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > 綜合 > 正文

POJO應用架構(gòu):Spring與EJB 3.0的對比

2024-07-21 02:15:12
字體:
供稿:網(wǎng)友

  愛因斯坦曾經(jīng)說過:"每件事物都應該盡可能簡單,而不是更簡單"。的確,對科學真理的追求都是為了簡化理論的根本假設,這樣我們才能處理真正麻煩的問題。企業(yè)級軟件的開發(fā)也是這樣的。

  簡化企業(yè)級軟件開發(fā)的關鍵是提供一個隱藏了復雜性(例如事務、安全性和永續(xù)性)的應用框架。良好設計的框架組件可以提升代碼的重復使用(reuse)能力,提高開發(fā)效率,從而得到更好的軟件質(zhì)量。但是,目前j2ee 1.4中的ejb 2.1框架組件被人們普遍認為是設計較差的和過于復雜的。java開發(fā)者對ejb 2.1很不滿,他們已經(jīng)試驗了多種其它的用于中間件服務傳送的方法。最引人注目的,下面兩個框架組件已經(jīng)引起開發(fā)者的巨大興趣和積極的反映。它們很可能成為未來企業(yè)級java應用程序可供選擇的框架組件。

  · spring框架組件是一個流行的,但是非標準的開放源代碼框架組件。它主要是由interface21 inc.公司開發(fā)和控制的。spring框架組件的架構(gòu)是基于依賴注入(di)設計模式的。spring可以單獨地或者與現(xiàn)有的應用程序服務器一起工作,它大量地使用xml配置文件。

  · ejb 3.0框架組件是一個標準的框架組件,由java社區(qū)組織(jcp)定義,并受到所有主流的j2ee廠商支持。預發(fā)布的ejb 3.0規(guī)范的開放源代碼和商業(yè)實現(xiàn)都可以在jboss和oracle上看到了。ejb 3.0大量使用java注釋(annotation)。

  這兩個框架組件的核心設計理念是相同的:兩者的目標都是把中間件服務傳遞給松散耦合的簡單舊式java對象(pojo)。這些框架組件通過在運行時截取執(zhí)行內(nèi)容或向pojo注入服務對象,把應用程序服務與pojo捆綁在一起。pojo本身不關心捆綁的過程,并且對框架組件幾乎沒有依賴。其結(jié)果是,開發(fā)者可以聚焦于業(yè)務邏輯,個人可以在沒有框架組件的情況下測試他們的pojo。此外,由于pojo不需要從框架組件中繼承或?qū)崿F(xiàn)框架組件接口,開發(fā)者建立繼承結(jié)構(gòu)和構(gòu)建應用程序的時候都有高度的靈活性。

  但是,盡管兩者的設計理念是相同的,它們傳遞pojo服務時卻采用了完全不同的方法。盡管目前已經(jīng)出版了大量的圖書和文章來把spring或ejb 3.0與ejb 2.1進行對比,但是它們都沒有對spring與ejb 3.0之間的差異進行認真的研究。在本文中,我將研究spring和ejb 3.0框架組件之間的關鍵差異,并討論它們的優(yōu)缺點。本文的主題也可以應用在其它一些名氣稍小的企業(yè)級中間件框架組件上,因為它們都聚焦于"松散耦合的pojo"設計。我希望本文能夠幫助你選擇符合需求的最佳的框架組件。
  廠商無關性(independence)

  開發(fā)者選擇某種java平臺的一個最重要的理由就是該平臺的廠商無關性。ejb 3.0是一個開放的、標準的、具有廠商無關性的平臺。ejb 3.0規(guī)范是由企業(yè)級java團體中所有主流開放源代碼和商業(yè)廠商開發(fā)和支持的。ejb 3.0框架組件把開發(fā)人員與應用程序服務器實現(xiàn)(implementation)隔離開來了。例如,盡管jboss的ejb 3.0實現(xiàn)是基于hibernate的,而oracle的ejb 3.0實現(xiàn)是基于toplink的,但是開發(fā)人員并不需要學習hibernate或toplink的特殊api,就可以讓他們的應用程序在jboss和oracle上運行。廠商無關性把ejb 3.0框架組件與其它的pojo中間件框架組件區(qū)分開來了。

  但是,很多ejb 3.0的批評家迅速指出,在寫這篇文章的時候,ejb 3.0規(guī)范還沒有達到最終發(fā)表的版本。在ejb 3.0被所有主流的j2ee廠商采用之前可能還需要一到兩年時間。但是,即使你的應用程序服務器還沒有自然地(natively)支持ejb 3.0,你還是可以通過下載和安裝一個"嵌入式的" ejb 3.0產(chǎn)品,在服務器上運行ejb 3.0應用程序。例如,jboss嵌入式ejb 3.0產(chǎn)品是開放源代碼的,可以在任何與j2se-5.0兼容的環(huán)境中(例如,在java應用程序服務器中)運行。它現(xiàn)在正在進行beta測試。其它的廠商也可能很快發(fā)布他們的嵌入式ejb 3.0產(chǎn)品,特別是用于規(guī)范的"數(shù)據(jù)永續(xù)性"部分的產(chǎn)品。

  另一方面,spring一直是非標準的技術(shù),而且在可以預見的未來它仍然是這樣的。盡管你可以把spring框架組件與任何應用程序服務器一起使用,但是spring應用程序都被"鎖定"在spring自身和你所選擇的集成到spring中的特定服務中了。

  · 盡管spring框架組件是一個開放源代碼項目,但是它仍然擁有配置文件的專利xml格式和專利編程接口。當然,這類"鎖定"發(fā)生在任何非標準的產(chǎn)品上,spring也不例外。但是它卻造成了:你的spring應用程序的長期生存能力依賴于spring項目本身(或interface21 inc公司,它雇傭了大多數(shù)spring核心開放人員)。此外,如果你使用任何spring特定的服務,例如spring事務管理器或spring mvc,你就被"鎖定"在這些api中了。

  · spring應用程序需要知道后臺的服務提供者。例如,對于數(shù)據(jù)持續(xù)(data persistence)服務來說,spring框架組件為jdbc、hibernate、ibatis和jdo使用了不同的dao和模板輔助類。因此,如果你希望為spring應用程序更換持續(xù)服務提供者(例如從jdbc切換到hibernate),你就必須重構(gòu)自己的應用程序代碼,使用新的輔助類。

  服務集成

  從較高的層次看,spring框架組件位于應用程序服務器和服務類庫之上。其服務集成代碼(例如數(shù)據(jù)訪問模板和輔助類)位于框架組件之中,并暴露給應用程序開發(fā)者。與此不同的是,ejb 3.0框架組件被緊密地集成到應用程序服務器中,服務集成代碼被封裝在標準的接口中。

  其結(jié)果是,ejb 3.0廠商可以積極地優(yōu)化總體性能和開發(fā)者體驗。例如,在jboss的 ejb 3.0實現(xiàn)中,使用entitymanager保持實體bean pojo的時候,下層hibernate對話事務會自動地與該調(diào)用方法的jta事務聯(lián)系在一起,當jta事務提交的時候,它也會提交。如果使用簡單的@persistencecontext注釋(本文后面有一個例子),你甚至于可以在有狀態(tài)的(stateful)對話bean中把entitymanager和它的下層hibernate事務捆綁到一個應用程序事務上。該應用程序事務在一個對話中跨越了多個線程,它在事務性的web應用程序(例如多頁面購物車)中是非常有效的。由于在jboss中,ejb 3.0框架組件、hibernate和tomcat緊密集成,上述的簡單和集成的編程接口才得以實現(xiàn)。oracle的ejb 3.0框架組件和其下層toplink持續(xù)服務之間的也實現(xiàn)了類似層次的集成。

  ejb 3.0中集成服務的另一個例子是群集(clustering)支持。如果你在服務器群集中部署ejb 3.0應用程序,那么所有的失效接續(xù)(fail-over)、負載均衡、分布式緩存和狀態(tài)復制服務都是可以自動地供應用程序使用的。下層群集服務都隱藏在ejb 3.0編程接口后面,它們對于ejb 3.0開發(fā)人員來說是完全透明的。

  在spring中,優(yōu)化框架組件與服務之間的交互操作要困難得多。例如,為了使用spring的宣告式事務服務來管理hibernate事務,你必須在xml配置文件中顯式地配置spring transactionmanager和hibernate sessionfactory對象。spring應用程序開發(fā)者必須顯式地管理跨多個http請求的事務。此外,要在spring應用程序中使用群集服務也沒有簡單的途徑。

  服務集成的靈活性

  由于spring中的服務集成代碼是作為編程接口的一部分暴露的,應用程序開發(fā)者可以根據(jù)需要靈活地集成服務。這個特性允許你集成自己的"輕量級"應用程序服務器。spring最普遍的使用方式是把tomcat和hibernate"粘合"在一起來提供簡單的數(shù)據(jù)庫驅(qū)動web應用程序。在這種情況下,spring自身提供事務服務,hibernate提供持續(xù)(persistence)服務--這種組織方式在spring中建立了一個微型應用程序服務器。

  ejb 3.0應用程序服務器沒有賦予你挑選服務的靈活性。在大多數(shù)情況中,你得到一組事先包裝好的特性,而你只需要其中的一部分。但是,如果應用程序服務器由模式化的內(nèi)部設計主導(類似jboss),那么你就可能把它分開,去掉一些不必要的特性。在任何情況下,定制成熟的應用程序服務器都不是一個簡單的事情。

  當然,如果應用程序的范圍超越了單節(jié)點,那么你可能需要捆綁來自普通應用程序服務器的服務(例如資源緩沖池、消息隊列和群集)。在總體的資源消耗方面,spring解決方案與任何ejb 3.0解決方案一樣,都是"重量級"的。

  在spring中,靈活的服務集成使得我們更容易把仿制(mock)對象(而不是實際的服務對象)捆綁到應用程序,用于在容器外部進行單元測試。在ejb 3.0應用程序中,大多數(shù)組件都是簡單的pojo,我們可以很容易地在容器外部測試這些它們。但是對于測試那些涉及到容器服務的對象(例如持續(xù)entitymanager),我們推薦在容器內(nèi)測試,因為比起仿制對象的方法,它們更簡單、更牢固、更精確。 xml與注釋的比較
從應用程序開發(fā)者的角度來看,spring的編程接口主要是基于xml配置文件的,而ejb 3.0廣泛使用了java注釋。xml文件可以表達復雜的關系,但是它們同時也很冗長、牢固程度也較低。注釋簡單明了,但是在注釋中我們卻很難表達復雜的或?qū)哟蔚慕Y(jié)構(gòu)。

  spring和ejb 3.0關于xml或注釋的選擇是依賴于這兩個框架組件后面的架構(gòu)的:由于注釋只能保存相當少的配置信息,只有預先集成的框架組件(類似在框架組件中已經(jīng)完成了大多數(shù)預備工作)可以廣泛地把注釋作為配置選項。我們已經(jīng)討論過了,ejb 3.0符合這種需求,而spring作為一個通用的di框架組件,不符合這個需求。

  當然,ejb 3.0和spring都在學習對方的最佳特性,它們都在某個程度上支持xml和注釋。例如,在ejb 3.0中xml配置文件是一個可選的重載機制,可以用于改變注釋的默認行為。注釋也可以用于配置某些spring服務。

  認識xml和注釋之間的區(qū)別的最好途徑是通過示例。在下一部分,我們會看到spring和ejb 3.0是如何為應用程序提供關鍵服務的。

  宣告式服務(declarative services)

  spring和ejb 3.0都把運行時服務(例如事務、安全性、日志記錄、消息和定制服務)捆綁到應用程序上。由于這些服務都沒有直接地與應用程序的業(yè)務邏輯相關聯(lián),因此它們不由應用程序自身來管理。作為代替,這些服務是在運行時由服務容器(例如spring或ejb 3.0)透明地應用在程序上的。開發(fā)者(或管理員)配置容器并告訴容器如何/什么時候應用服務。

  ejb 3.0使用java注釋配置宣告式服務,而spring使用xml配置文件。在大多數(shù)情況下,對于這類服務,ejb 3.0注釋方法更加簡單,更加優(yōu)雅。下面是一個在ejb 3.0中給pojo方法應用事務服務的例子。

public class foo {

@transactionattribute(transactionattributetype.required)
public bar () {
// 執(zhí)行某些操作 ...
}
}


  你也可以在一個代碼片斷中定義多個屬性,應用多個服務。下面是一個在ejb 3.0中同時給pojo應用了事務和安全性服務的例子:

@securitydomain("other")
public class foo {

@rolesallowed({"managers"})
@transactionattribute(transactionattributetype.required)
public bar () {
// 執(zhí)行某些操作 ...
}
}


  使用xml指定代碼屬性和配置宣告式服務可能導致冗長的和不穩(wěn)定的配置文件。下面是一個在spring應用程序中利用xml元素給foo.bar()方法應用一個非常簡單的hibernate事務服務的例子:

<!-- setup the transaction interceptor -->
<bean id="foo"
class="org.springframework.transaction
.interceptor.transactionproxyfactorybean">

<property name="target">
<bean class="foo"/>
</property>

<property name="transactionmanager">
<ref bean="transactionmanager"/>
</property>

<property name="transactionattributesource">
<ref bean="attributesource"/>
</property>
</bean>

<!-- setup the transaction manager for hibernate -->
<bean id="transactionmanager"
class="org.springframework.orm
.hibernate.hibernatetransactionmanager">

<property name="sessionfactory">
<!-- you need to setup the sessionfactory bean in
yet another xml element -- omitted here -->
<ref bean="sessionfactory"/>
</property>
</bean>

<!-- specify which methods to apply transaction -->
<bean id="transactionattributesource"
class="org.springframework.transaction
.interceptor.namematchtransactionattributesource">

<property name="properties">
<props>
<prop key="bar">
</props>
</property>
</bean>


  如果你給同一個pojo添加多個攔截器(interceptor,例如安全性攔截器),那么xml的復雜程度會呈幾何級數(shù)增長。spring意識到了只使用xml配置文件的局限性,它現(xiàn)在支持在java源代碼中使用apache通用元數(shù)據(jù)指定事務屬性。在最新的spring 1.2中,還支持jdk-1.5樣式的注釋。如果你要使用事務元數(shù)據(jù),就需要把上面的transactionattributesource bean改變成attributestransactionattributesource示例,并增加與元數(shù)據(jù)攔截器相關的額外配置。

<bean id="autoproxy"
class="org.springframework.aop.framework.autoproxy
.defaultadvisorautoproxycreator"/>
<bean id="transactionattributesource"
class="org.springframework.transaction.interceptor
.attributestransactionattributesource"
autowire="constructor"/>
<bean id="transactioninterceptor"
class="org.springframework.transaction.interceptor
.transactioninterceptor"
autowire="bytype"/>
<bean id="transactionadvisor"
class="org.springframework.transaction.interceptor
.transactionattributesourceadvisor"
autowire="constructor"/>
<bean id="attributes"
class="org.springframework.metadata.commons
.commonsattributes"/>


  當你擁有很多事務方法的時候,spring元數(shù)據(jù)簡化了transactionattributesource元素。但是它沒有解決xml配置文件的基本問題--冗長和脆弱,還是需要使用事務攔截器、transactionmanager和transactionattributesource。

  依賴注入(dependency injection)

  中間件容器的關鍵優(yōu)勢在于它們允許開發(fā)者建立松散耦合的應用程序。服務的客戶端只需要知道服務的接口。容器用具體的實現(xiàn)來初始化服務對象,并使客戶端能夠訪問它們。這就允許了容器在不同的服務實現(xiàn)之間進行切換,而不需要改變接口或客戶端代碼。

  依賴注入(di)模式是實現(xiàn)松散耦合的應用程序的最好的方法之一。它比舊方法(例如通過jndi的依賴查找或容器回調(diào))更易于使用、更優(yōu)雅。使用di的時候,框架組件充當建立服務對象的對象工廠,并根據(jù)運行時配置,把這些服務對象注入應用程序pojo中。從應用程序開發(fā)者的角度來看,當客戶端pojo需要使用某種服務對象的時候,它們會自動地獲取該對象。

  spring和ejb 3.0都給di模式提供了廣泛的支持,但是它們之間有一些深刻的差異。spring支持普通的、但是復雜的、基于xml配置文件的di api;ejb 3.0通過簡單的注釋支持大多數(shù)通用服務對象(例如ejb和上下文關系對象)和jndi對象的注入操作。

  ejb 3.0 di注釋非常簡潔,易于使用。@resource標簽注入大多數(shù)通用服務對象和jndi對象。下面的例子演示了如何把jndi中的服務器的默認datasource對象注入pojo的一個字段變量中。defaultds是jndi用于表示datasource的名稱。在第一次使用mydb變量之前,會把正確的值自動地賦給它。

public class foodao {

@resource (name="defaultds")
datasource mydb;

// 使用 mydb 獲取數(shù)據(jù)庫的jdbc連接
}


  作為對字段變量直接注入的補充,我們還可以使用ejb 3.0中的@resource注釋,通過設置(setter)方法來注入對象。例如,下面的例子就注入了一個對話上下文關系(context)對象。應用程序一直沒有顯式調(diào)用設置方法--該方法在被其它的任何方法調(diào)用之前,會先被容器調(diào)用。

@resource
public void setsessioncontext (sessioncontext ctx) {
sessionctx = ctx;
}


  對于更加復雜的服務對象,已經(jīng)定義了一些專用的注入注釋。例如,@ejb注釋用于注入ejb stub,@persistencecontext注釋用于注入entitymanager對象(它為ejb 3.0實體bean處理數(shù)據(jù)庫訪問)。下面的例子演示了如何向一個有狀態(tài)的對話bean注入entitymanager對象。@persistencecontext注釋的type屬性指明被注入的entitymanager擁有擴展的事務上下文關系--它不會自動地與jta事務管理器一起提交,因此它可以用于那些在一個對話中跨越多個線程的應用程序事務。

@stateful
public class foobean implements foo, serializable {

@persistencecontext(
type=persistencecontexttype.extended
)
protected entitymanager em;

public foo getfoo (integer id) {
return (foo) em.find(foo.class, id);
}
}


  ejb 3.0規(guī)范定義了可以通過注釋注入的服務器資源。但是它不支持用戶自定義的應用程序pojo的彼此相互注入。

  在spring中,你首先需要為pojo的服務對象定義一個設置方法(或者帶參數(shù)的構(gòu)造函數(shù))。下面的例子顯示pojo需要一個指向hibernate對話工廠的指針。

public class foodao {

hibernatetemplate hibernatetemplate;

public void sethibernatetemplate (hibernatetemplate ht) {
hibernatetemplate = ht;
}

// 使用 hibernate 模板訪問數(shù)據(jù)
public foo getfoo (integer id) {
return (foo) hibernatetemplate.load (foo.class, id);
}
}


  接下來,你可以指定容器如何在運行時通過xml元素鏈獲取服務對象并把它捆綁到pojo上。下面的例子演示了把數(shù)據(jù)源捆綁到hibernate對話工廠,把對話捆綁到hibernate模板對象,最后把模板對象捆綁到應用程序pojo的xml元素。這段spring代碼如此復雜的部分原因在于我們必須手動地注入下層hibernate管道對象,而ejb 3.0 entitymanager是由服務器自動地管理和配置的。但是這又讓我們回到了spring沒有像ejb 3.0那樣與服務緊密集成的討論中了。

<bean id="datasource"
class="org.springframework
.jndi.jndiobjectfactorybean">
<property name="jndiname">
<value>java:comp/env/jdbc/mydatasource</value>
</property>
</bean>

<bean id="sessionfactory"
class="org.springframework.orm
.hibernate.localsessionfactorybean">
<property name="datasource">
<ref bean="datasource"/>
</property>
</bean>

<bean id="hibernatetemplate"
class="org.springframework.orm
.hibernate.hibernatetemplate">
<property name="sessionfactory">
<ref bean="sessionfactory"/>
</property>
</bean>

<bean id="foodao" class="foodao">
<property name="hibernatetemplate">
<ref bean="hibernatetemplate"/>
</property>
</bean>

<!-- the hibernatetemplate can be injected
into more dao objects -->


  盡管在spring中基于xml的依賴注入語法是復雜的,但是它卻很強大。你可以把任何pojo(包括你在應用程序中定義的)注入另一個pojo。如果你真的希望在ejb 3.0應用程序中使用spring的依賴注入能力,你可以通過jndi把spring bean工廠注入ejb中。在某些ejb 3.0應用程序服務器中,廠商可能定義了額外的非標準的api,以注入任意的pojo。其中一個很好的例子是jboss microcontainer,它甚至比spring更普通,因為它處理了面向方面編程(aop)的依賴性。

  結(jié)論

  盡管spring和ejb 3.0的目標都是為松散耦合的pojo提供企業(yè)級服務,但是它們是使用截然不同的方法來達到這個目標的。在這兩個框架組件中都大量地使用了依賴注入(di)。

  使用ejb 3.0的時候,基于標準的方法、注釋的大量使用、以及與應用程序服務器的緊密集成形成了強大的廠商無關性和開發(fā)者的高效率。使用spring的時候,一致地使用依賴注入和集中的xml配置文件,允許開發(fā)者構(gòu)造更加靈活的應用程序,并在同一時刻使用多個應用服務。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 镇远县| 寻甸| 塔城市| 兴城市| 永寿县| 布尔津县| 安福县| 河源市| 瑞安市| 广昌县| 虞城县| 龙南县| 乌兰县| 曲阜市| 顺平县| 威远县| 图片| 泰兴市| 寿光市| 东明县| 简阳市| 来宾市| 洱源县| 辰溪县| 肇庆市| 孝昌县| 历史| 信宜市| 宁城县| 比如县| 阿拉善右旗| 隆昌县| 辽宁省| 嘉祥县| 清丰县| 峨山| 钟祥市| 东港市| 革吉县| 密山市| 磴口县|