<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    常言笑的家

    Spring, Hibernate, Struts, Ajax, RoR

    POJO應用架構:Spring與EJB 3.0的對比

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

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

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

      · EJB 3.0框架組件是一個標準的框架組件,由Java社區組織(JCP)定義,并受到所有主流的J2EE廠商支持。預發布的EJB 3.0規范的開放源代碼和商業實現都可以在JBoss和Oracle上看到了。EJB 3.0大量使用Java注釋(annotation)。

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

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

      廠商無關性(Independence)

      開發者選擇某種Java平臺的一個最重要的理由就是該平臺的廠商無關性。EJB 3.0是一個開放的、標準的、具有廠商無關性的平臺。EJB 3.0規范是由企業級Java團體中所有主流開放源代碼和商業廠商開發和支持的。EJB 3.0框架組件把開發人員與應用程序服務器實現(implementation)隔離開來了。例如,盡管JBoss的EJB 3.0實現是基于Hibernate的,而Oracle的EJB 3.0實現是基于TopLink的,但是開發人員并不需要學習Hibernate或TopLink的特殊API,就可以讓他們的應用程序在JBoss和Oracle上運行。廠商無關性把EJB 3.0框架組件與其它的POJO中間件框架組件區分開來了。

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

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

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

      · Spring應用程序需要知道后臺的服務提供者。例如,對于數據持續(data persistence)服務來說,Spring框架組件為JDBC、Hibernate、iBatis和JDO使用了不同的DAO和模板輔助類。因此,如果你希望為Spring應用程序更換持續服務提供者(例如從JDBC切換到Hibernate),你就必須重構自己的應用程序代碼,使用新的輔助類。

      服務集成

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

      其結果是,EJB 3.0廠商可以積極地優化總體性能和開發者體驗。例如,在JBoss的 EJB 3.0實現中,使用EntityManager保持實體BeanPOJO的時候,下層Hibernate對話事務會自動地與該調用方法的JTA事務聯系在一起,當JTA事務提交的時候,它也會提交。如果使用簡單的@PersistenceContext注釋(本文后面有一個例子),你甚至于可以在有狀態的(stateful)對話bean中把EntityManager和它的下層Hibernate事務捆綁到一個應用程序事務上。該應用程序事務在一個對話中跨越了多個線程,它在事務性的Web應用程序(例如多頁面購物車)中是非常有效的。由于在JBoss中,EJB 3.0框架組件、Hibernate和Tomcat緊密集成,上述的簡單和集成的編程接口才得以實現。Oracle的EJB 3.0框架組件和其下層Toplink持續服務之間的也實現了類似層次的集成。

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

      在Spring中,優化框架組件與服務之間的交互操作要困難得多。例如,為了使用Spring的宣告式事務服務來管理Hibernate事務,你必須在XML配置文件中顯式地配置Spring TransactionManager和Hibernate SessionFactory對象。Spring應用程序開發者必須顯式地管理跨多個HTTP請求的事務。此外,要在Spring應用程序中使用群集服務也沒有簡單的途徑。

      服務集成的靈活性

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

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

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

      在Spring中,靈活的服務集成使得我們更容易把仿制(mock)對象(而不是實際的服務對象)捆綁到應用程序,用于在容器外部進行單元測試。在EJB 3.0應用程序中,大多數組件都是簡單的POJO,我們可以很容易地在容器外部測試這些它們。但是對于測試那些涉及到容器服務的對象(例如持續EntityManager),我們推薦在容器內測試,因為比起仿制對象的方法,它們更簡單、更牢固、更精確。 XML與注釋的比較
    從應用程序開發者的角度來看,Spring的編程接口主要是基于XML配置文件的,而EJB 3.0廣泛使用了Java注釋。XML文件可以表達復雜的關系,但是它們同時也很冗長、牢固程度也較低。注釋簡單明了,但是在注釋中我們卻很難表達復雜的或層次的結構。

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

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

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

            宣告式服務(Declarative Services)

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

      EJB 3.0使用Java注釋配置宣告式服務,而Spring使用XML配置文件。在大多數情況下,對于這類服務,EJB 3.0注釋方法更加簡單,更加優雅。下面是一個在EJB 3.0中給POJO方法應用事務服務的例子。

    public class Foo {

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public bar () {
    // 執行某些操作 ...
    }
    }

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

    @SecurityDomain("other")
    public class Foo {

    @RolesAllowed({"managers"})
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public bar () {
    // 執行某些操作 ...
    }
    }

      使用XML指定代碼屬性和配置宣告式服務可能導致冗長的和不穩定的配置文件。下面是一個在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的復雜程度會呈幾何級數增長。Spring意識到了只使用XML配置文件的局限性,它現在支持在Java源代碼中使用Apache通用元數據指定事務屬性。在最新的Spring 1.2中,還支持JDK-1.5樣式的注釋。如果你要使用事務元數據,就需要把上面的transactionAttributeSource bean改變成AttributesTransactionAttributeSource示例,并增加與元數據攔截器相關的額外配置。

    <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元數據簡化了transactionAttributeSource元素。但是它沒有解決XML配置文件的基本問題--冗長和脆弱,還是需要使用事務攔截器、transactionManager和transactionAttributeSource。

      依賴注入(Dependency Injection)

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

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

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

      EJB 3.0 DI注釋非常簡潔,易于使用。@Resource標簽注入大多數通用服務對象和JNDI對象。下面的例子演示了如何把JNDI中的服務器的默認DataSource對象注入POJO的一個字段變量中。DefaultDS是JNDI用于表示DataSource的名稱。在第一次使用myDb變量之前,會把正確的值自動地賦給它。

    public class FooDao {

    @Resource (name="DefaultDS")
    DataSource myDb;

    // 使用 myDb 獲取數據庫的JDBC連接
    }

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

    @Resource
    public void setSessionContext (SessionContext ctx) {
    sessionCtx = ctx;
    }

      對于更加復雜的服務對象,已經定義了一些專用的注入注釋。例如,@EJB注釋用于注入EJB stub,@PersistenceContext注釋用于注入EntityManager對象(它為EJB 3.0實體bean處理數據庫訪問)。下面的例子演示了如何向一個有狀態的對話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規范定義了可以通過注釋注入的服務器資源。但是它不支持用戶自定義的應用程序POJO的彼此相互注入。

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

    public class FooDao {

    HibernateTemplate hibernateTemplate;

    public void setHibernateTemplate (HibernateTemplate ht) {
    hibernateTemplate = ht;
    }

    // 使用 Hibernate 模板訪問數據
    public Foo getFoo (Integer id) {
    return (Foo) hibernateTemplate.load (Foo.class, id);
    }
    }

      接下來,你可以指定容器如何在運行時通過XML元素鏈獲取服務對象并把它捆綁到POJO上。下面的例子演示了把數據源捆綁到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)的依賴性。

      結論

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

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

    posted on 2007-05-10 09:00 常言笑 閱讀(430) 評論(0)  編輯  收藏 所屬分類: JAVA/J2EE

    My Links

    Blog Stats

    常用鏈接

    留言簿(5)

    隨筆分類

    隨筆檔案

    搜索

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: jjzz亚洲亚洲女人| 欧洲精品99毛片免费高清观看| 久久免费观看国产99精品| 四虎www免费人成| 亚洲熟妇丰满多毛XXXX| 久久综合亚洲色hezyo| 国产免费不卡v片在线观看| 亚洲91av视频| 久久精品电影免费动漫| 国产亚洲精品国产| 国产麻豆一精品一AV一免费| 久久精品夜色噜噜亚洲A∨| 亚洲av无码一区二区三区在线播放 | 亚洲男人第一无码aⅴ网站| 亚洲另类无码一区二区三区| 亚洲第一成年免费网站| 亚洲一欧洲中文字幕在线| 亚洲啪啪免费视频| 国产精品亚洲午夜一区二区三区| 13小箩利洗澡无码视频网站免费| 亚洲人成网站在线观看播放| 国产一精品一av一免费爽爽| 亚洲国产日韩一区高清在线| 91成人免费在线视频| 456亚洲人成影院在线观| 成年人在线免费观看| 亚洲国产成人片在线观看| 国产精品九九久久免费视频| 在线日韩日本国产亚洲| 久久久久av无码免费网| 亚洲中文字幕一二三四区| 浮力影院亚洲国产第一页| 久久久久久AV无码免费网站 | 一级午夜免费视频| 午夜亚洲国产理论秋霞| 国产高清在线精品免费软件| 一区二区三区免费电影| 亚洲AV无码久久久久网站蜜桃 | 日韩插啊免费视频在线观看| 精品久久亚洲中文无码| 亚洲伦乱亚洲h视频|