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

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

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

    posts - 56, comments - 54, trackbacks - 0, articles - 4
       ::  ::  :: 聯系 :: 聚合  :: 管理
    轉載地址:?
    http://forum.javaeye.com/viewtopic.php?t=4919? 中文
    http://www.theserverside.com/tt/articles/article.tss?l=SpringFramework?英文

    Introducing to Spring Framework


    作者:Rod Johnson
    譯者:yanger,taowen
    校對:taowen

    關于Spring Framework,今年夏天你可能已經聽見很多的議論。在本文中,我將試圖解釋Spring能完成什么,和我怎么會認為它能幫助你開發J2EE應用程序。

    又來一個framework?

    你可能正在想“不過是另外一個的framework”。當已經有許多開放源代碼(和專有) J2EE framework時,為什么你還要耐下心子讀這篇文章或去下載Spring Framework?

    我相信Spring是獨特的,有幾個原因:


      它關注的領域是其他許多流行的Framework未曾關注的。Spring要提供的是一種管理你的業務對象的方法。

      Spring既是全面的又是模塊化的。Spring有分層的體系結構,這意味著你能選擇僅僅使用它任何一個獨立的部分,而它的架構又是內部一致。因此你能從你的學習中,得到最大的價值。例如,你可能選擇僅僅使用Spring來簡單化JDBC的使用,或用來管理所有的業務對象。

      它的設計從一開始就是要幫助你編寫易于測試的代碼。Spring是使用測試驅動開發的工程的理想框架。

    Spring不會給你的工程添加對其他的框架依賴。Spring也許稱得上是個一站式解決方案,提供了一個典型應用所需要的大部分基礎架構。它還涉及到了其他framework沒有考慮到的內容。

    盡管它僅僅是一個從2003年2月才開始的開源項目,但Spring有深厚的歷史根基。這個開源工程是起源自我在2002年晚些時候出版的《Expert One-on-One J2EE設計與開發》書中的基礎性代碼。這本書展示了Spring背后的基礎性架構思想。然而,對這個基礎架構的概念可以追溯到2000年的早些時候,并且反映了我為一系列商業工程開發基礎結構的成功經驗。

    2003年1月,Spring已經落戶于SourceForge上了。現在有10個開發人員,其中6個是高度投入的積極分子。

    Spring架構上的好處

    在我們進入細節之前,讓我們來看看Spring能夠給工程帶來的種種好處:


      Spring能有效地組織你的中間層對象,不管你是否選擇使用了EJB。如果你僅僅使用了Struts或其他為J2EE的 API特制的framework,Spring致力于解決剩下的問題。

      Spring能消除在許多工程中常見的對Singleton的過多使用。根據我的經驗,這是一個很大的問題,它降低了系統的可測試性和面向對象的程度。

      通過一種在不同應用程序和項目間一致的方法來處理配置文件,Spring能消除各種各樣自定義格式的屬性文件的需要。曾經對某個類要尋找的是哪個魔法般的屬性項或系統屬性感到不解,為此不得不去讀Javadoc甚至源編碼?有了Spring,你僅僅需要看看類的JavaBean屬性。Inversion of Control的使用(在下面討論)幫助完成了這種簡化。

      通過把對接口編程而不是對類編程的代價幾乎減少到沒有,Spring能夠促進養成好的編程習慣。

      Spring被設計為讓使用它創建的應用盡可能少的依賴于他的APIs。在Spring應用中的大多數業務對象沒有依賴于Spring。

      使用Spring構建的應用程序易于單元測試。

      Spring能使EJB的使用成為一個實現選擇,而不是應用架構的必然選擇。你能選擇用POJOs或local EJBs來實現業務接口,卻不會影響調用代碼。

      Spring幫助你解決許多問題而無需使用EJB。Spring能提供一種EJB的替換物,它們適用于許多web應用。例如,Spring能使用AOP提供聲明性事務管理而不通過EJB容器,如果你僅僅需要與單個數據庫打交道,甚至不需要一個JTA實現。

      Spring為數據存取提供了一個一致的框架,不論是使用的是JDBC還是O/R mapping產品(如Hibernate)。

    Spring確實使你能通過最簡單可行的解決辦法來解決你的問題。而這是有有很大價值的。

    Spring做了些什么?

    Spring提供許多功能,在此我將依次快速地展示其各個主要方面。

    任務描述

    首先,讓我們明確Spring范圍。盡管Spring覆蓋了許多方面,但我們對它應該涉什么,什么不應該涉及有清楚的認識。

    Spring的主要目的是使J2EE易用和促進好編程習慣。

    Spring不重新輪子。因此,你發現在Spring中沒有logging,沒有連接池,沒有分布式事務調度。所有這些東西均有開源項目提供(例如我們用于處理所有日志輸出的Commons Logging以及Commons DBCP),或由你的應用程序服務器提供了。出于同樣的的原因,我們沒有提供O/R mapping層。對于這個問題已經有了像Hibernate和JDO這樣的優秀解決方案。

    Spring的目標就是讓已有的技術更加易用。例如,盡管我們沒有底層事務協調處理,但我們提供了一個抽象層覆蓋了JTA或任何其他的事務策略。

    Spring沒有直接和其他的開源項目競爭,除非我們感到我們能提供新的一些東西。例如,象許多開發人員一樣,我們從來沒有對Struts感到高興過,并且覺得到在MVC web framework中還有改進的余地。在某些領域,例如輕量級的IoC容器和AOP框架,Spring確實有直接的競爭,但是在這些領域還沒有已經較為流行的解決方案。(Spring在這些領域是開路先鋒。)

    Spring也得益于內在的一致性。所有的開發者都在唱同樣的的贊歌,基礎想法依然與Expert One-on-One J2EE設計與開發中提出的差不多。 并且我們已經能夠在多個領域中使用一些中心的概念,例如Inversion of Control。

    Spring在應用服務器之間是可移植的。當然保證可移植性總是一種挑戰,但是我們避免使用任何平臺特有或非標準的東西,并且支持在WebLogic,Tomcat,Resin,JBoss,WebSphere和其他的應用服務器上的用戶。

    Inversion of Control 容器

    Spring設計的核心是 org.springframework.beans 包, 它是為與JavaBeans一起工作而設計的。 這個包一般不直接被用戶使用,而是作為許多其他功能的基礎。

    下一個層面高一些的抽象是"Bean Factory"。一個Spring bean factory 是一個通用的Factory,它使對象能夠按名稱獲取,并且能管理對象之間的關系。

    Bean factories 支持兩種模式的對象:


      Singleton:在此模式中,有一個具有特定名稱的共享對象實例,它在查找時被獲取。這是默認的,而且是最為經常使用的。它對于無狀態對象是一種理想的模式。

      Prototype:在此模式中,每次獲取將創建一個獨立的對象。例如,這可以被用于讓用戶擁有他們自己的對象。


    由于 org.springframwork.beans.factory.BeanFactory是一個簡單的接口,它能被大量底層存儲方法實現。你能夠方便地實現你自己的BeanFactory,盡管很少用戶需要這么做。最為常用的BeanFactory定義是:


      XmlBeanFactory: 可解析簡單直觀的定義類和命名對象屬性的XML結構。 我們提供了一個DTD來使編寫更容易。

      ListableBeanFactoryImpl:提供了解析存放在屬性文件中的bean定義的能力,并且可通過編程創建BeanFactories。

    每個bean定義可能是一個POJO(通過類名和JavaBean初始屬性定義),或是一個FactoryBean。FactoryBean接口添加了一個間接層。通常,這用于創建使用AOP或其他方法的代理對象:例如,添加聲明性事務管理的代理。(這在概念上和EJB的interception相似,但實現得更簡單。)

    BeanFactories能在一個層次結構中選擇性地參與,繼承ancestor(祖先)的定義。這使得在整個應用中公共配置的共享成為可能,雖然個別資源,如controller servlets,還擁有他們自己的獨立的對象集合。

    這種使用JavaBeans的動機在《Expert One-on-One J2EE Design and Development》的第四章中有描述,在TheServerSide網站上的有免費的PDF版本(http://www.theserverside.com/resources/article.jsp?l=RodJohnsonInterview)。

    通過BeanFactory概念,Spring成為一個Inversion of Control的容器。(我不怎么喜歡container這個詞,因為它使人聯想到重量級容器,如EJB容器。Spring的BeanFactory是一個可通過一行代碼創建的容器,并且不需要特殊的部署步驟。)

    Inversion of Control背后的概念經常表述為Hollywood原則的:“Don’t call me, I’ll call you。” IoC將控制創建的職責搬進了框架中,并把它從應用代碼脫離開來。涉及到配置的地方,意思是說在傳統的容器體系結構中,如EJB,一個組件可以調用容器并問“我需要它給我做工作的對象X在哪里?”;使用IoC容器則只需指出組件需要X對象,在運行時容器會提供給它。容器是通過查看方法的參數表(例如JavaBean的屬性)做到的,也可能根據配置數據如XML。

    IoC有幾個重要的好處,例如:


      因為組件不需要在運行時間尋找合作者,所以他們可以更簡單的編寫和維護。在Spring版的IoC里,組件通過暴露JavaBean的setter方法表達他們依賴的其他組件。這相當于EJB通過JNDI來查找,EJB查找需要開發人員編寫代碼。

      同樣原因,應用代碼更容易測試。JavaBean屬性是簡單的,屬于Java核心的,并且是容易測試的:僅編寫一個自包含的Junit測試方法用來創建對象和設置相關屬性即可。

      一個好的IoC實現保留了強類型。如果你需要使用一個通用的factory來尋找合作者,你必須通過類型轉換將返回結果轉變為想要的類型。這不是一個大不了的問題,但是不雅觀。使用IoC,你在你的代碼中表達了強類型依賴,框架將負責類型轉換。這意味著在框架配置應用時,類型不匹配將導致錯誤;在你的代碼中,你無需擔心類型轉換異常。

      大部分業務對象不依賴于IoC容器的APIs。這使得很容易使用遺留下來的代碼,且很容易的使用對象無論在容器內或不在容器內。例如,Spring用戶經常配置Jakarta Commons DBCP數據源為一個Spring bean:不需要些任何定制代碼去做這件事。我們說一個IoC容器不是侵入性的:使用它并不會使你的代碼依賴于它的APIs。任何JavaBean在Spring bean factory中都能成為一個組件。

    最后應該強調的是,IoC 不同于傳統的容器的體系結構,如EJB,應用代碼最小程度地依靠于容器。這意味著你的業務對象可以潛在的被運行在不同的IoC 框架上——或者在任何框架之外——不需要任何代碼的改動。

    以我和其他Spring用戶的經驗來說,再怎么強調IoC給應用程序代碼帶來的好處也不為過。

    IoC不是一個新概念,但是它在J2EE團體里面剛剛到達黃金時間。 有一些可供選擇的IoC 容器: 例如 Apache Avalon, PicoContainer 和 HiveMind。Avalon 從沒怎么流行,盡管它很強大而且有很長的歷史。Avalon相當的重和復雜,并且看起來比新的IoC解決方案更具侵入性。 PicoContainer是一個輕量級而且更強調通過構造函數表達依賴性而不是JavaBean 屬性。 與Spring不同,它的設計允許每個類型一個對象的定義(可能是因為它拒絕任何Java代碼外的元數據導致的局限性)。在Spring, PicoContainer 和其他 IoC frameworks之間做比較,可參看文章Spring網站上的"The Spring Framework - A Lightweight Container"位于http://www.springframework.org/docs/lightweight_container.html。這個頁面里面包含了PicoContainer站點的鏈接 。

    Spring BeanFactories 是非常輕量級的。用戶已經成功地將他們應用在applets和單獨的Swing應用中。(它們也很好地工作在EJB容器中。) 沒有特殊的部署步驟和察覺得到的啟動時間。這個能力表明一個容器在應用的任何層面幾乎立即可以發揮非常大的價值。

    Spring BeanFactory 概念貫穿于Spring始終, 而且是Spring如此內在一致的關鍵原因。在IoC容器中,Spring也是唯一的,它使用IoC作為基礎概念貫穿于整個功能豐富的框架。

    對應用開發人員,最重要的是,一個或多個BeanFactory提供了一個定義明確的業務對象層。這類似于local session bean層,但比它更簡單。與EJBs不同,在這個層中的對象可能是相關的,并且他們的關系被擁有它們的factory管理。有一個定義明確的業務對象層對于成功的體系結構是非常重要的。

    Spring ApplicationContext 是BeanFactory的子接口,為下列東西提供支持:


      信息查找,支持著國際化

      事件機制,允許發布應用對象以及可選的注冊以接收到事件

      可移植的文件和資源訪問

    XmlBeanFactory 例子

    Spring用戶通常在XML的“bean定義”文件中配置他們的應用。Spring的XML bean定義文檔的根是<beans> 元素。該元素包含一個或多個 <bean>定義。我們一般給每個bean定義的指定類和屬性。我們還必須指定ID作為標識,這將成為在代碼中使用該bean的名字。

    讓我們來看一個簡單的例子,它配置了三個應用程序對象,之間的關系在J2EE應用中常常能夠看到:


      J2EE DataSource

      使用DataSource的DAO

      在處理過程中使用DAO的業務對象

    在下面的例子中,我們使用一個來自Jakarta Commons DBCP項目的BasicDataSource。這個class(和其他許多已有的class一樣)可以簡單地被應用在Spring bean factory中,只要它提供了JavaBean格式的配置。需要在shutdown時被調用的Close方法可通過Spring的"destroy-method"屬性被注冊,以避免BasicDataSource需要實現任何Spring 的接口。

    java代碼:?

    <beans>

    ? <bean id="myDataSource"
    class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    ? ? <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
    ? ? <property name="url"><value>jdbc:mysql://localhost:3306/mydb</value></property>
    ? ? <property name="username"><value>root</value></property>
    ? </bean>


    BasicDataSource中我們感興趣的所有屬性都是String類型的,因此我們用<value>元素來指定他們的值。如果必要的話,Spring使用標準的 JavaBean屬性編輯器機制來把String轉換為其他的類型。

    現在,我們定義DAO,它有一個對DataSource的bean引用。Bean間關系通過<ref>元素來指定:

    java代碼:?

    <bean id="exampleDataAccessObject"
    ? ? ? ? ? ? ? ? class="example.ExampleDataAccessObject">
    ? ? <property name="dataSource"><ref bean="myDataSource"/></property>
    ? </bean>

    The business object has a reference to the DAO, and an int property (exampleParam):
    <bean id="exampleBusinessObject"
    ? ? ? ? ? ? ? ? class="example.ExampleBusinessObject">
    ? ? <property name="dataAccessObject"><ref bean="exampleDataAccessObject"/></property>
    ? ? <property name="exampleParam"><value>10</value></property>
    ? </bean>

    </beans>


    對象間的關系一般在配置中明確地設置,象這個例子一樣。我們認為這樣做是件好事情。然而Spring還提供了我們稱做"autowire"的支持, 一個la PicoContainer,其中它指出了bean間的依賴關系。這樣做的局限性——PicoContainer也是如此——是如果有一個特殊類型的多個Bean,要確定那個類型所依賴的是哪個實例是不可能。好的方面是,不滿足的依賴可以在factory初始化后被捕獲到。(Spring 也為顯式的配置提供了一種可選的依賴檢查,它可以完成這個目的)

    在上面的例子中,如果我們不想顯式的編寫他們的關系,可使用如下的autowire特性:

    java代碼:?

    <bean id="exampleBusinessObject"
    ? ? ? ? class="example.ExampleBusinessObject"
    ? ? ? ? autowire="byType">

    ? ? <property name="exampleParam"><value>10</value></property>
    </bean>



    使用這個特性,Spring會找出exampleBusinessObject的dataSource屬性應該被設置為在當前BeanFactory中找到的DataSource實現。在當前的BeanFactory中,如果所需要類型的bean不存在或多于一個,將產生一個錯誤。我們依然要設置exampleParam屬性,因為它不是一個引用。

    Autowire支持和依賴檢查剛剛加入CVS并將在Spring 1.0 M2(到10/20,2003)中提供。本文中所討論的所有其他特性都包含在當前1.0 M1版本中。

    把管理從Java代碼中移出來比硬編碼有很大的好處,因為這樣可以只改變XML文件而無需改變一行Java代碼。例如,我們可以簡單地改變myDataSource的bean定義引用不同的bean class以使用別的連接池,或者一個用于測試的數據源。 XML節變成另一種,我們可以用Spring的JNDI location FactoryBean從應用服務器獲取一個數據源。

    現在讓我們來看看例子中業務對象的java 代碼。注意下面列出的代碼中沒有對Spring的依賴。不像EJB容器,Spring BeanFactory不具有侵入性:在應用對象里面你通常不需要對Spring的存在硬編碼。

    java代碼:?

    publicclass ExampleBusinessObject implements MyBusinessObject {

    ? ? ? ? private ExampleDataAccessObject dao;
    ? ? ? ? privateint exampleParam;

    ? ? ? ? publicvoid setDataAccessObject(ExampleDataAccessObject dao){
    ? ? ? ? ? ? ? ? this.dao = dao;
    ? ? ? ? }

    ? ? ? ? publicvoid setExampleParam(int exampleParam){
    ? ? ? ? ? ? ? ? this.exampleParam = exampleParam;
    ? ? ? ? }

    ? ? ? ? publicvoid myBusinessMethod(){
    ? ? ? ? ? ? ? ? // do stuff using dao
    ? ? ? ? }
    }


    注意那些property setter,它們對應于bean定義文檔中的XML引用。這些將在對象被使用之前由Spring調用。

    這些應用程序的bean不需要依賴于Spring:他們不需要實現任何Spring的接口或者繼承Spring的類。他們只需要遵守JavaBeans的命名習慣。在Spring 應用環境之外重用它們是非常簡單的,例如,在一個測試環境中。只需要用它們的缺省構造函數實例化它們,并且通過調用setDataSource()和setExampleParam()手工設置它的屬性。如果你想以一行代碼支持程序化的創建,只要你有一個無參數的構造器,你就可以自由定義其他需要多個屬性的構造函數。

    注意在業務接口中沒有聲明將會一起使用的JavaBean屬性。 他們是一個實現細節。我們可以“插入”帶有不同bean屬性的不同的實現類而不影響連接著的對象或者調用的代碼。

    當然,Spring XML bean factories 有更多的功能沒有在這里描述,但是,應當讓你對基本使用有了一些感覺。以及,簡單的屬性,有JavaBean屬性編輯器的屬性,Spring可以自動處理lists,maps和java.util.Properties。

    Bean factories 和application contexts 通常和J2EE server定義的一個范圍相關聯,例如:


      Servlet context.:在spring 的MVC 框架里, 每一個包含common objects的web 應用都定義有一個應用程序的context。Spring提供了通過listener或者servlet實例化這樣的context的能力而不需要依賴于Spring 的MVC 框架,因而它也可以用于Struts,WebWork 或者其他的web框架之中。

      A Servlet:在Spring MVC 框架里每一個servlet控制器都有它自己的應用程序context,派生于根(全應用程序范圍的)應用程序context。在Struts或者其他MVC框架中實現這些也很容意。

      EJB:Spring 為EJB提供方便的超類,它們簡化了EJB的創建并且提供了一個從EJB Jar 文件中的XML文檔載入的BeanFactory。

    這些J2EE規范提供的hook通常避免了使用Singleton來創造一個bean factory。

    然而,如果我們愿意的話可以用代碼創建一個BeanFactory,雖然是沒有什么意義的。例如,我們在以下三行代碼中可以創建bean factory并且得到一個業務對象的引用:

    java代碼:?

    InputStream is = getClass().getResourceAsStream("myFile.xml");
    XmlBeanFactory bf = new XmlBeanFactory(is);
    MyBusinessObject mbo = (MyBusinessObject) bf.getBean("exampleBusinessObject");



    這段代碼將能工作在一個應用服務器之外:甚至不依賴J2EE,因為Spring 的IoC容器是純java的。


    JDBC 抽象和數據存儲異常層次

    數據訪問是Spring 的另一個閃光點。

    JDBC 提供了還算不錯的數據庫抽象,但是需要用痛苦的API。這些問題包括:

      需要冗長的錯誤處理代碼來確保ResultSets,Statements以及(最重要的)Connections在使用后關閉。這意味著對JDBC的正確使用可以快速地導致大量的代碼量。它還是一個常見的錯誤來源。Connection leak可以在有負載的情況下快速宕掉應用程序。

      SQLException相對來說不能說明任何問題。JDBC不提供異常的層次,而是用拋出SQLException來響應所有的錯誤。找出到底哪里出錯了——例如,問題是死鎖還是無效的SQL?——要去檢查SQLState或錯誤代碼。這意味著這些值在數據庫之間是變化的。

    Spring用兩種方法解決這些問題:

      提供API,把冗長乏味和容易出錯的異常處理從程序代碼移到框架之中。框架處理所有的異常處理;程序代碼能夠集中精力于編寫恰當的SQL和提取結果上。

      為你本要處理SQLException程序代碼提供有意義的異常層次。當Spring第一次從數據源取得一個連接時,它檢查元數據以確定數據庫。它使用這些信息把SQLException映射為自己從org.springframework.dao.DataAccessException派生下來的類層次中正確的異常。因而你的代碼可以與有意義的異常打交道,并且不需要為私有的SQLState或者錯誤碼擔心。Spring的數據訪問異常不是JDBC特有的,因而你的DAO并不一定會因為它們可能拋出的異常而綁死在JDBC上。

    Spring提供兩層JDBC API。第一個時,在org.springframework.jdbc.core包中,使用回調機制移動控制權——并且因而把錯誤處理和連接獲取和釋放——從程序的代碼移到了框架之中。這是一種不同的Inversion of Control,但是和用于配置管理的幾乎有同等重要的意義。

    Spring使用類似的回調機制關注其他包含特殊獲取和清理資源步驟的API,例如JDO(獲取和釋放是由PersistenceManager完成的),事務管理(使用JTA)和JNDI。Spring中完成這些回調的類被稱作template。

    例如,Spring的JdbcTemplate對象能夠用于執行SQL查詢并且在如下的列表中保存結果:

    java代碼:?

    JdbcTemplate template = new JdbcTemplate(dataSource);
    finalList names = newLinkedList();
    template.query("SELECT USER.NAME FROM USER",
    ? ? ? ? new RowCallbackHandler(){
    ? ? ? ? ? ? ? ? publicvoid processRow(ResultSet rs)throwsSQLException{
    ? ? ? ? ? ? ? ? ? ? ? ? names.add(rs.getString(1));
    ? ? ? ? ? ? ? ? }
    ? ? ? ? });



    注意回調中的程序代碼是能夠自由拋出SQLException的:Spring將會捕捉到這些異常并且用自己的類層次重新拋出。程序的開發者可以選擇哪個異常,如果有的話,被捕捉然后處理。

    JdbcTemplate提供許多支持不同情景包括prepared statements和批量更新的方法。Spring的JDBC抽象有比起標準JDBC來說性能損失非常小,甚至在當應用中需要的結果集數量很大的時候。

    在org.springframework.jdbc.object包中是對JDBC的更高層次的抽象。這是建立在核心的JDBC回調功能基礎紙上的,但是提供了一個能夠對RDBMS操作——無論是查詢,更新或者是存儲過程——使用Java對象來建模的API。這個API部分是受到JDO查詢API的影響,我發現它直觀而且非常有用。

    一個用于返回User對象的查詢對象可能是這樣的:

    java代碼:?


    class UserQuery extends MappingSqlQuery {

    ? ? ? ? public UserQuery(DataSource datasource){
    ? ? ? ? ? ? ? ? super(datasource, "SELECT * FROM PUB_USER_ADDRESS WHERE USER_ID = ?");
    ? ? ? ? ? ? ? ? declareParameter(new SqlParameter(Types.NUMERIC));
    ? ? ? ? ? ? ? ? compile();
    ? ? ? ? }

    ? ? ? ? // Map a result set row to a Java object
    ? ? ? ? protectedObject mapRow(ResultSet rs, int rownum)throwsSQLException{
    ? ? ? ? ? ? ? ? User user = new User();
    ? ? ? ? ? ? ? ? user.setId(rs.getLong("USER_ID"));
    ? ? ? ? ? ? ? ? user.setForename(rs.getString("FORENAME"));
    ? ? ? ? ? ? ? ? return user;
    ? ? ? ? }

    ? ? ? ? public User findUser(long id){
    ? ? ? ? ? ? ? ? // Use superclass convenience method to provide strong typing
    ? ? ? ? ? ? ? ? return(User) findObject(id);
    ? ? ? ? }
    }


    這個類可以在下面用上:
    java代碼:?


    User user = userQuery.findUser(25);


    這樣的對象經常可以用作DAO的inner class。它們是線程安全的,除非子類作了一些超出常規的事情。

    在org.springframework.jdbc.object包中另一個重要的類是StoredProcedure類。Spring讓存儲過程通過帶有一個業務方法的Java類進行代理。如果你喜歡的話,你可以定義一個存儲過程實現的接口,意味著你能夠把你的程序代碼從對存儲過程的依賴中完全解脫出來。

    Spring數據訪問異常層次是基于unchecked(運行時)exception的。在幾個工程中使用了Spring之后,我越來越確信這個決定是正確的。

    數據訪問異常一般是不可恢復的。例如,如果我們不能鏈接到數據庫,某個業務對象很有可能就不能完成要解決的問題了。一個可能的異常是optimistic locking violation,但是不是所有的程序使用optimistic locking。強制編寫捕捉其無法有效處理的致命的異常通常是不好的。讓它們傳播到上層的handler,比如servlet或者EJB 容器通常更加合適。所有的Spring對象訪問異常都是DataAccessException的子類,因而如果我們確實選擇了捕捉所有的Spring數據訪問異常,我們可以很容易做到這點。

    注意如果我們確實需要從unchecked數據訪問異常中恢復,我們仍然可以這么做。我們可以編寫代碼僅僅處理可恢復的情況。例如,如果我們認為只有optimistic locking violation是可恢復的,我們可以在Spring的DAO中如下這么寫:

    java代碼:?


    try{
    ? ? ? ? // do work
    }
    catch(OptimisticLockingFailureException ex){
    ? ? ? ? // I'm interested in this
    }


    如果Spring的數據訪問異常是checked的,我們需要編寫如下的代碼。注意我們還是可以選擇這么寫:
    java代碼:?


    try{
    ? ? ? ? // do work
    }
    catch(OptimisticLockingFailureException ex){
    ? ? ? ? // I'm interested in this
    }
    catch(DataAccessException ex){
    ? ? ? ? // Fatal; just rethrow it
    }


    第一個例子的潛在缺陷是——編譯器不能強制處理可能的可恢復的異常——這對于第二個也是如此。因為我們被強制捕捉base exception(DataAccessException),編譯器不會強制對子類(OptimisticLockingFailureException)的檢查。因而編譯器可能強制我們編寫處理不可恢復問題的代碼,但是對于強制我們處理可恢復的問題并未有任何幫助。

    Spring對于數據訪問異常的unchecked使用和許多——可能是大多數——成功的持久化框架是一致的。(確實,它部分是受到JDO的影響。)JDBC是少數幾個使用checked exception的數據訪問API之一。例如TopLink和JDO大量使用unchecked exception。Gavin King現在相信Hibernate也應該選擇使用unchecked exception。

    Spring的JDBC能夠用以下辦法幫助你:


      你決不需要在使用JDBC時再編寫finally block。

      總的來說你需要編寫的代碼更少了

      你再也不需要挖掘你的RDBMS的文檔以找出它為錯誤的列名稱返回的某個罕見的錯誤代碼。你的程序不再依賴于RDBMS特有的錯誤處理代碼。

      無論使用的是什么持久化技術,你都會發現容易實現DAO模式,讓業務代碼無需依賴于任何特定的數據訪問API。

    在實踐中,我們發現所有這些都確實有助于生產力的提高和更少的bug。我過去常常厭惡編寫JDBC代碼;現在我發現我能夠集中精力于我要執行的SQL,而不是煩雜的JDBC資源管理。

    如果需要的話Spring的JDBC抽象可以獨立使用——不強迫你把它們用作Spring的一部分。

    O/R mapping 集成

    當然你經常需要使用O/R mapping,而不是使用關系數據訪問。你總體的應用程序框架也必須支持它。因而提供了對Hibernate 2.x和JDO的集成支持。它的數據訪問架構使得它能和任何底層的數據訪問技術集成。Spring和Hibernate集成得尤其好。

    為什么你要使用Hibernate加Spring,而不是直接使用Hibernate?


      Session 管理 Spring提供有效率的,簡單的以并且是安全的處理Hibernate Session。使用Hibernate的相關代碼為了效率和恰當的事務處理一般需要使用相同的Hibernate “Session”對象。Spring讓它容易透明地創建和綁定Session到當前的線程,要么使用聲明式,AOP的method interceptor方法,要么在Java代碼層面使用顯式的,“template”包裝類。因而Spring解決了在Hibernate論壇上經常出現的用法問題。

      資源管理 Spring的應用程序context能夠處理Hiberante SessionFactories的位置和配置,JDBC數據源和其他相關資源。這使得這些值易于管理和改變。

      集成的事務管理 Spring讓你能夠把你的Hibernate代碼包裝起來,要么使用聲明式,AOP風格的method interceptor,要么在Java代碼層面顯式使用“template”包裝類。在兩種做法中,事務語義都為你處理了,并且在異常時也做好了恰當的事務處理(回滾,等)。如下面討論的,你還獲得了能夠使用和替換不同transaction manager,而不會讓你相關Hibernate代碼受到影響的能力。額外的,JDBC相關的代碼能夠完全事務性的和Hibernate代碼集成。這對于處理沒有在Hibernate實現的功能很有用。

      如上描述的異常包裝 Spring能夠包裝Hibernate異常,把它們從私有的,checked異常轉換為一套抽象的運行時異常。這使得你能夠僅僅在恰當的層面處理大部分不可恢復的持久化異常,而不影響樣板catch/throw,和異常聲明。你仍然能夠在任何你需要的地方捕捉和處理異常。記住JDBC異常(包括DB特有的方言)也被轉換到相同的層次中,意味著你能在一致的編程模型中對JDBC執行相同的操作。

      為了避免和廠商綁定 Hibernate是強大的,靈活的,開放源代碼并且免費,但是它仍然使用私有的API。給出了一些選擇,使用標準或者抽象API實現主要的程序功能通常是你想要的,當你需要因為功能,性能,或者其他考慮要轉換到使用其他實現時。

      讓測試變簡單 Spring的Inversion of Control方法使得改變Hibernate的session factories,數據源,transaction manager的實現和位置很容易,如果需要的話還能改變mapper object的實現。這使得更加容易分離和測試持久化相關的代碼。

      事務管理
      抽象出一個數據訪問的API是不夠的;我們還需要考慮事務管理。JTA是顯而易見的選擇,但是它是一個直接用起來很笨重的API,因而許多J2EE開發者感到EJB CMT是對于事務管理唯一合理的選擇。

      Spring提供了它自己對事務管理的抽象。Spring提供了這些:


        通過類似于JdbcTemplate的回調模板編程管理事務,比起直接使用JTA要容易多了

        類似于EJB CMT的聲明式事務管理,但是不需要EJB容器

      Spring的事務抽象式唯一的,它不綁定到JTA或者任何其他事務管理技術。Spring使用事務策略的概念把程序代碼和底層的事務架構(例如JDBC)解藕。

      為什么你要關心這些?JTA不是所有事務管理的最好答案嗎?如果你正在編寫僅僅使用一個數據庫的程序,你不需要JTA的復雜度。你不關心XA事務或者兩階段提交。你甚至不需要提供這些東西的高端應用服務器。但是另一方面,你不會希望在需要和多個數據源打交道的時候重寫你的代碼。

      假定你決定通過直接使用JDBC或者Hibernate的事務以避免JTA帶來的額外負擔。一旦你需要處理多個數據源,你必須剝開所有的事務管理代碼并且使用JTA事務來替代。這不是非常有吸引力的并且導致大部分J2EE程序員,包括我自己,推薦只使用全局JTA事務。然而使用Spring事務抽象,你只需要重新配置Spring讓它使用JTA,而不是JDBC或者Hibernate的事務策略,就一切OK了。這是一個配置上的改變,而不是代碼的改動。因而,Spring使得你能夠自由縮放應用。

      AOP

      最近在應用AOP來解決企業關注點方面大家有了很大的興趣,例如事務管理,這些都是EJB所要解決的。

      Spring的AOP支持的首要目標是要給POJOs提供J2EE服務。這類似于JBoss 4的目標,Spring AOP由它能夠在應用服務器之間移植的優勢,因而沒有綁死在廠商身上的風險。它既可以在web或者EJB容器中使用,也能夠在WebLogic,Tomcat,JBoss,Resin,Jetty,Orion和許多其他應用服務器和web容器上使用。

      Spring AOP支持method interception。所支持關鍵的AOP概念包括:


        Interception:自定義行為能夠在對接口和類的調用之前和之后插入。這類似于AspectJ術語中類似的“around advice”。

        Introduction:指定advice會導致對象實現額外的接口。這混亂了繼承。

        靜態和動態的pointcuts:在interception發生的程序執行處指定points。靜態pointcuts concern函數簽名;動態pointcuts也可以在point被求值的地方考慮函數的參數。Pointcuts獨立interceptors單獨定義,使得標準interceptor可以應用于不同應用程序和代碼上下文。

      Spring既支持有狀態(一個advised對象一個實例)也支持無狀態的interceptors(所有advice使用一個實例)。

      Spring不支持field interception。這是一個經過深思熟慮的設計決定。我總是感覺field interception違反了封裝。我比較傾向于把AOP作為補全物,而不是與OOP沖突的東西。如果在5年或者10年后,我們在AOP學習曲線上走得更遠了并且覺得應該在程序設計的桌面上給AOP一個位置,我不會驚訝的。(然而在那個時候基于語言的解決方案例如AspectJ可能比它們今天看來更加具有吸引力。)

      Spring使用動態代理實現AOP(其中存在一個接口)或者在運行時使用CGLIB生成字節碼(這使得能夠代理類)。兩種方法都能夠在任何應用服務器中使用。

      Spring是第一個實現AOP Alliance interfaces的AOP 框架(www.sourceforge.net/projects/aopalliance)。這些是定義在不同AOP框架中能夠互操作interceptors的嘗試。

      在TheServerSide和其他地方有一個正在進行但是不是那么引人注目的爭論,就是這種interception是不是“true AOP”。我倒不怎么在意它叫什么;僅僅需要知道它是否在實踐中有用就好了。我也樂于稱它為“declarative middleware”(聲明式中間件)。把Spring AOP認做簡單,輕量級的無狀態beans的替代物,這樣就不需要monolithic EJB容器了,而這些僅僅是讓你能夠構建有你需要的服務的容器。我不推薦advising任何一個POJO,對local SLSBs的類比有助于你理解推薦的粒度。(然而,與EJB不同的是,在恰當但是少見的情況下,你可以自由地把Spring的AOP應用到粒度更好的對象上。)

      因為Spring在實例上advises 對象,而不是在class loader層面上,使用有不同advice的同一個類的多個實例是可能的,或者與advised實例一道使用unadvised 實例。

      可能Spring AOP最常見的應用是聲明式事務管理。這是基于前面描述的TansactionTemplate抽象上的,并且可以給任何POJO提供聲明式事務管理。取決于事務策略,底層的機制可以是JTA,JDBC,Hibernate或者任何其他提供事務管理的API。

      Spring的聲明式事務管理類似于EJB CMT,在以下方面有些不同:


        事務管理能夠應用于任何POJO。我們推薦業務對象實現接口,但是這只是一個好的編程習慣的問題,而不是由框架強制的。

        通過使用Spring的事務API能夠在事務性POJO中實現編程回調。我們為此提供靜態的方法,使用ThreadLoacal變量,因而你不需要傳播諸如EJBContext這樣的context對象來確保回滾。

        你可以聲明式地定義“回滾規則”。EJB不會在未捕捉程序異常的時候自動回滾(僅僅在unchecked exceptions和其他Throwables的時候),應用程序開發者經常需要在任何異常發生時回滾。Spring事務管理讓你能夠聲明式地指定什么異常什么子類能夠導致自動回滾。缺省的行為和EJB是一致的,但是你能夠在checked和unchecked異常時自動回滾。這個在最少化自編程回調代碼方面有很大好處,而回調依賴于Spring的事務API(因為EJB的編程回調時在EJBContext中完成的)。

        事務管理不綁定于JTA。如前面解釋過的,Spring的事務管理能夠在不同事務策略中使用。

      當然還可以使用Spring AOP實現程序特有的aspects。取決于你對AOP概念的接受程度,決定你是否選擇這么做,而不是Spring的能力,但是它確實非常有用。我們所見過的成功例子包括:


        自定義的security interception,當安全檢查的復雜度超出了J2EE安全架構的能力的時候

        在開發中使用的調試和profiling aspects

        發送email通知管理員用戶不尋常的舉動的Interceptors

      程序自定的aspects能夠成為消除需要許多函數的樣板代碼的有利武器。

      Spring AOP透明地與Spring BeanFactory概念集成。包含一個來自Spring BeanFactory對象地代碼不需要知道它是還是不是advised。和任何對象一樣,契約實在接口和對象實現中定義的。

      下面的XML片斷展示了如何定義一個AOP代理:
      java代碼:?


      <bean id="myTest"
      ? ? ? ? class="org.springframework.aop.framework.ProxyFactoryBean">
      ? ? ? ? <property name="proxyInterfaces">
      ? ? ? ? ? ? ? ? <value>org.springframework.beans.ITestBean</value>
      ? ? ? ? </property>
      ? ? ? ? <property name="interceptorNames">
      ? ? ? ? ? ? ? ? <list>
      ? ? ? ? ? ? ? ? ? ? ? ? <value>txInterceptor</value>
      ? ? ? ? ? ? ? ? ? ? ? ? <value>target</value>
      ? ? ? ? ? ? ? ? </list>
      ? ? ? ? </property>
      </bean>


      注意bean類的定義總是AOP框架的ProxyFactoryBean,雖然bean的類型在引用中使用或者由BeanFactory的getBean()方法返回時依賴的是代理接口。(多個代理方法是被支持的。)ProxyFactoryBean的“interceptorNames”屬性需要一個字符串列表。(因為如果代理是一個“prototype”而不是singleton,有狀態interceptors可能需要創建新的實例,所以必須使用Bean的名字而不是bean的引用。)列表中的名字可以是interceptor或者pointcuts(interceptors和有關它們合適被使用的信息)。列表中的“target”值自動創建一個“invoker interceptor”封裝target對象。實現代理接口的是在factory中的bean的名字。這個例子中的myTest可以和其他bean factory中的bean一樣使用。例如,其他對象可以使用<ref>元素引用它而且這些引用是由Spring IoC設置的。

      還可以不用BeanFactory,編程構建AOP代理,雖然這個很少用得上:

      java代碼:?


      TestBean target = new TestBean();
      DebugInterceptor di = new DebugInterceptor();
      MyInterceptor mi = new MyInterceptor();
      ProxyFactory factory = new ProxyFactory(target);
      factory.addInterceptor(0, di);
      factory.addInterceptor(1, mi);
      // An "invoker interceptor" is automatically added to wrap the target
      ITestBean tb = (ITestBean) factory.getProxy();


      我們相信最好把程序裝配從Java代碼中移出來,而AOP也不例外。

      Spring在它的AOP能力方面的直接競爭者是Jon Tirsen的Nanning Aspects(http://nanning.codehaus.org)。

      我覺得AOP作為EJB的替代無提供企業服務這個用法方面的進步是重要的。隨著時間,這將成為Spring很重要的關注點。

      MVC web 框架

      Spring包括一個強大而且高度可配置的MVC web 框架。

      Spring的MVC model類似于Struts。在多線程服務對象這點上,Spring的Controller類似于Struts Action,只有一個實例處理所有客戶的請求。然而,我們相信Spring的MVC比起Struts有很多優點,例如:


        Spring在controllers,JavaBean,models和views提供了一個非常清晰的劃分。

        Spring的MVC是非常靈活的。不像Struts,它強制你的Action和Form對象進入固化的層次之中(因而你迫使你使用Java的實體繼承),Spring MVC完全是基于接口的。而且,通過插入你自己的接口幾乎Spring MVC 框架的所有部分都是可配置的。當然我們也提供了方便的類作為實現選擇。

        Spring MVC是真正的view無關的。你不會被強制使用JSP,如果你不想那么做的話。你可以使用Velocity,XSLT或其他view技術。如果你想要使用自定義的view機制——例如,你自己的模板語言——你可以簡單實現Spring的View接口并且把它集成進來。

        和其他對象一樣,Spring的Controllers是通過IoC配置的。著使得它們易于測試,并且完美地和其他由Spring管理的對象集成。

        Web層變成了業務對象層之上的薄薄一層。這鼓勵了好的習慣。Struts和其他專門的web框架讓你去實現你自己的業務對象;Spring提供了你應用程序所有層的集成。

      如在Struts 1.1中所見的,你可以有和你在Spring MVC 應用程序中所需要的一樣多的dispatcher servlets。

      下面的例子展示了一個簡單的Spring Controller如何能夠訪問定義在應用程序context中的業務對象。這個controller在它的handleRequest()方法中執行了Google搜索:

      java代碼:?


      publicclass GoogleSearchController
      ? ? ? ? ? ? ? ? implements Controller {

      ? ? ? ? private IGoogleSearchPort google;

      ? ? ? ? privateString googleKey;

      ? ? ? ? publicvoid setGoogle(IGoogleSearchPort google){
      ? ? ? ? ? ? ? ? this.google = google;
      ? ? ? ? }

      ? ? ? ? publicvoid setGoogleKey(String googleKey){
      ? ? ? ? ? ? ? ? this.googleKey = googleKey;
      ? ? ? ? }

      ? ? ? ? public ModelAndView handleRequest(
      ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? HttpServletRequest request, HttpServletResponse response)
      ? ? ? ? ? ? ? ? throws ServletException, IOException{
      ? ? ? ? ? ? ? ? String query = request.getParameter("query");
      ? ? ? ? ? ? ? ? GoogleSearchResult result =
      ? ? ? ? ? ? ? ? ? ? ? ? // Google property definitions omitted...

      ? ? ? ? ? ? ? ? ? ? ? ? // Use google business object
      ? ? ? ? ? ? ? ? ? ? ? ? google.doGoogleSearch(this.googleKey, query,
      ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? start, maxResults, filter, restrict,
      ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? safeSearch, lr, ie, oe);

      ? ? ? ? ? ? ? ? returnnew ModelAndView("googleResults", "result", result);
      ? ? ? ? }
      }


      這段代碼使用的prototype中,IGoogleSearchPort是一個GLUE web services代理,由Spring FActoryBean返回。然而,Spring把controller從底層web service庫中分離出來。接口可以使用普通的Java對象,test stub,mock對象或者如下面要討論的EJB代理實現。這個contorller不包括資源查找;除了支持它的web交互的必要代碼之外沒有別的什么了。

      Spring還提供了數據綁定,forms,wizards和更復雜的工作流的支持。

      對Spring MVC 框架的優秀簡介是Thomas Risberg的Spring MVC 教程(http://www.springframework.org/docs/MVC-step-by-step/Spring-MVC-step-by-step.html)。還可以參見“Web MVC with the Spring Framework”(http://www.springframework.org/docs/web_mvc.html)。

      如果你樂于使用你鐘情的MVC框架,Spring的分層架構使得你能夠使用Spring的其他部分而不用MVC層。我們有使用Spring做中間層管理和數據訪問,但是在web層使用Struts,WebWork或者Tapestry的用戶。

      實現EJB

      如果你選擇使用EJB,Spring能在EJB實現和客戶端訪問EJB兩方面都提供很大的好處。

      對業務邏輯進行重構,把它從EJB facades中取出到POJO已經得到了廣泛的認同。(不講別的,這使得業務邏輯更容易單元測試,因為EJB嚴重依賴于容器而難于分離測試。)Spring為session bean和message driver bean提供了方便的超類,使得通過自動載入基于包含在EJB Jar文件中的XML文檔BeanFactory讓這變得很容易。

      這意味著stateless session EJB可以這么獲得和使用所需對象:

      java代碼:?


      import org.springframework.ejb.support.AbstractStatelessSessionBean;

      publicclass MyEJB extends AbstractStatelessSessionBean
      ? ? ? ? ? ? ? ? ? ? ? ? implements MyBusinessInterface {
      ? ? ? ? private MyPOJO myPOJO;

      ? ? ? ? protectedvoid onEjbCreate(){
      ? ? ? ? ? ? ? ? this.myPOJO = getBeanFactory().getBean("myPOJO");
      ? ? ? ? }

      ? ? ? ? publicvoid myBusinessMethod(){
      ? ? ? ? ? ? ? ? this.myPOJO.invokeMethod();
      ? ? ? ? }
      }


      假定MyPOJO是一個接口,它的實現類——以及任何它需要的配置,注入基本的屬性和更多的合作者——在XML bean factory 定義中隱藏。

      我們通過在ejb-jar.xmldeployment descriptor中名為ejb/BeanFactoryPath的環境變量定義告訴Spring去哪兒裝載XML文檔。如下:

      java代碼:?


      <session>
      ? ? ? ? <ejb-name>myComponent</ejb-name>
      ? ? ? ? <local-home>com.test.ejb.myEjbBeanLocalHome</local-home>
      ? ? ? ? <local>com.mycom.MyComponentLocal</local>
      ? ? ? ? <ejb-class>com.mycom.MyComponentEJB</ejb-class>
      ? ? ? ? <session-type>Stateless</session-type>
      ? ? ? ? <transaction-type>Container</transaction-type>

      ? ? ? ? <env-entry>
      ? ? ? ? ? ? ? ? <env-entry-name>ejb/BeanFactoryPath</env-entry-name>
      ? ? ? ? ? ? ? ? <env-entry-type>java.lang.String</env-entry-type>
      ? ? ? ? ? ? ? ? <env-entry-value>/myComponent-ejb-beans.xml</env-entry-value></env-entry>
      ? ? ? ? </env-entry>
      </session>


      myComponent-ejb-beans.xml 文件將會從classpath裝載:在本例中,是EJB Jar文件的根目錄。每個EJB都能指定自己的XML文檔,因而這個機制能在每個EJB Jar文件中使用多次。

      Spring 的超類實現了EJB中諸如setSessionContext()和ejbCreate()的生命周期管理的方法,讓應用程序開發者只需選擇是否實現Spring的onEjbCreate()方法。

      使用EJB

      Spring還讓實現EJB變得更加容易。許多EJB程序使用Service Locator和Business Delegate模式。這些比在客戶代碼中遍布JNDI查找強多了,但是它們常見的實現方式有顯著的缺點,例如:


        使用EJB的典型代碼依賴Service Locator或者Business Delegate singletons,使得測試難于進行。

        在Service Locator模式沒有使用Business Delegate的情況下,程序代碼還要在EJB home中調用create()方法,并且處理可能導致的異常。因而仍然綁定在EJB API身上,忍受著EJB 編程模型的復雜度。

        實現Business Delegate模式通常導致顯著的代碼重復,其中我們必須編寫大量僅僅是調用EJB同等方法的方法。

      基于這些和其他原因,傳統的EJB訪問,如在Sun Adventure Builder和OTN J2EE Virtual Shopping Mall中展示的那樣,會降低生產率并且帶來顯著的復雜度。

      Spring通過引入codeless business delegate前進了一步。有了Spring,你不再需要再編寫另一個Service Locator,另一個JNDI查找,或者在硬編碼的Business Delegate中重復代碼,除非你肯定這增加了價值。

      例如,假定我們有使用local EJB的web controller。我們將遵循最佳實踐,使用EJB Business Methods Interface模式,EJB的local interface extend非EJB專有的業務方法接口。(這么做的主要的一個原因是確保在本地接口和bean實現類中方法簽名的自動同步。)讓我們調用這個業務方法接口MyComponent。當然我們還需要實現local home接口并且提供實現SessionBean和MyComponent業務方法的bean的實現類。

      用了Spring EJB 訪問,我們把我們的web層controller和EJB實現掛接上所需要進行的Java編碼僅僅是在我們的controller中暴露一個類型MyComponent的setter方法。這將如下保存作為實例變量的引用:

      java代碼:?


      private MyComponent myComponent;

      publicvoid setMyComponent(MyComponent myComponent){
      ? ? ? ? this.myComponent = myComponent;
      }


      我們隨后在任何業務方法中使用這個實例變量。

      Spring自動完稱剩下的工作,通過像這樣的XML bean定義。LocalStatelessSessionProxyFactoryBean是一個可以用于任何EJB的通用factory bean。它創建的對象能夠自動被Spring轉型為MyComponent類型。

      java代碼:?


      <bean id="myComponent"
      class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">

      ? ? ? ? <property name="jndiName"><value>myComponent</value></property>
      ? ? ? ? <property name="businessInterface"><value>com.mycom.MyComponent</value></property>
      </bean>

      <bean id="myController"
      ? ? ? ? class = "com.mycom.myController"
      >
      ? ? ? ? <property name="myComponent"><ref bean="myComponent"/></property>
      </bean>


      在幕后有許多魔法般的事情發生,Spring AOP framework的殷勤,雖然不強迫你使用AOP的概念享受這些結果。“myComponent”bean定義為EJB創建一個代理,它實現了業務方法的接口。EJB local home在啟動的時候被緩存,因而只需要一次JNDI查找。每次EJB被調用的時候,代理調用local EJB中的create()方法并且調用EJB中對應的業務方法。

      myController bean定義為這個代理設置controller類的myController屬性。

      這個EJB訪問機制極大簡化了應用程序的代碼:


        Web層的代碼不依賴于EJB的使用。如果你想要使用POJO,mock object或者其他test stub替代EJB引用,我們可以簡單地改動一下myComponent bean定義而不影響一行Java代碼

        我們還不需要寫一行JNDI查找或者其他EJB plumbing code。

      在實際程序中的性能測試和經驗標明這種方法(包括對目標EJB的反射調用)的性能影響是很小的,在典型的應用中檢測不出。記住無論如何我們都不希望使用fine-grained的EJB調用,因為會有有關應用服務器上的EJB的底層架構方面的代價。

      我們可以把相同方法應用于遠程EJB,通過類似org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean factory bean的方法。然而我們無法隱藏遠程EJB的業務方法接口中的RemoteException。

      測試

      如你可能已經注意到的,我和其他Spring開發這是全面單元測試重要性的堅定支持者。我們相信框架被徹底單元測試過的是非常重要的,而且我們框架設計的主要目標是讓建立在框架之上的程序易于單元測試。

      Spring自身有一個極好的單元測試包。我們的1.0 M1的單元測試覆蓋率是75%,而且我們希望在1.0 RC1的時候能夠達到80%的單元測試覆蓋率。我們發現在這個項目中測試優先的開發帶來的好處是實實在在的。例如,它使得作為國際化分布式開發團隊的工作極端有效率,而且用戶評論CVS snapshots趨向于穩定和使用安全。

      因為以下理由,我們相信用Spring構建的應用程序是非常易于測試的:


        IoC推動了單元測試

        應用程序不包括直接使用注入JNDI的J2EE服務的plumbing code,這些代碼一般讓測試難于進行

        Spring bean factories和contexts能夠在容器外設置

      在容器外可以設置Spring bean factory的能力提供了對開發過程有趣的可選項。在幾個使用Spring的web應用中,工作是從定義業務接口和在web容器外集成測試開始的。在業務功能已經足夠完整之后,web接口不過是添加在其上的薄薄一層。

      誰在使用Spring

      雖然相對來說Spring還是一個新的項目,但是我們已經有了一個令人印象深刻并且不斷增長的用戶群。它們已經有許多產品使用著Spring。用戶包括一個主要的全球投資銀行(做大型項目的),一些知名的網絡公司,幾個web開發顧問機構,衛生保健公司,以及學院機構。

      許多用戶完整地使用Spring,但是一些只單獨使用一些組件。例如,大量用戶使用我們地JDBC或者其他數據訪問功能。

      Roadmap

      在今年晚些時候我們主要要做的是讓Spring發布release 1.0。然而,我們還有一些更長遠的目標。

      為1.0 final規劃地主要改進式源代碼級地元數據支持,它主要用于(但不局限于)AOP框架。這將使得C#風格的attribute驅動的事務管理,并且讓聲明式企業服務在典型應用情況下非常容易配置。Attribute支持將會在Spring的1.0 final release支持中加入,并且設計的是在發布的那個時候能與JSR-175集成。

      1.0之后,一些可能的改進地方包括:


        通過對我們的JDBC和事務支持的一個相當抽象來支持JMS

        支持bean factories的動態重配置

        提供web services的能力

        IDE和其他工具支持

      作為一個敏捷項目,我們主要是受到用戶需求的驅動。因而我們不會開發沒有一個用戶需要的特性,并且我們會仔細傾聽來自用戶群的聲音。

      總結

      Spring是一個解決了許多在J2EE開發中常見的問題的強大框架。

      Spring提供了管理業務對象的一致方法并且鼓勵了注入對接口編程而不是對類編程的良好習慣。Spring的架構基礎是基于使用JavaBean屬性的Inversion of Control容器。然而,這僅僅是完整圖景中的一部分:Spring在使用IoC容器作為構建完關注所有架構層的完整解決方案方面是獨一無二的。

      Spring提供了唯一的數據訪問抽象,包括簡單和有效率的JDBC框架,極大的改進了效率并且減少了可能的錯誤。Spring的數據訪問架構還集成了Hibernate和其他O/R mapping解決方案。

      Spring還提供了唯一的事務管理抽象,它能夠在各種底層事務管理技術,例如JTA或者JDBC紙上提供一個一致的編程模型。

      Spring提供了一個用標準Java語言編寫的AOP框架,它給POJOs提供了聲明式的事務管理和其他企業事務——如果你需要——還能實現你自己的aspects。這個框架足夠強大,使得應用程序能夠拋開EJB的復雜性,同時享受著和傳統EJB相關的關鍵服務。

      Spring還提供了可以和總體的IoC容器集成的強大而靈活的MVC web框架。


      更多信息

      參見以下資源獲得關于Spring的更多信息:


        Expert One-on-One J2EE Design and Development(Rod Johnson,Wrox,2002)。雖然Spring在書出版之后已經極大地進步和改進了,它仍然是理解Spring動機的極佳途徑。

        Spring的主頁:http://www.springframework.org。這里包括Javadoc和幾個教程。

        在Sourceforge上的論壇和下載

        Spring用戶和Spring開發者的郵件列表

      我們正在盡我們可能去改進Spring的文檔和示例。我們還為在信件和郵件列表中極好的回復率自豪。我們希望你能快速融入我們的社區!

      關于作者

      Rod Johnson 作為Java開發者和架構師已經有了7年的經驗了并且在J2EE平臺出現之初就在其上進行開發了。他是《Expert One-on-One J2EE Design and Development》(Wrox,2002)的作者并且貢獻了其他好幾本關于J2EE的書。他當前正在為Wiley撰寫另外一本有關J2EE架構的書。Rod在兩個Java標準委員會服務并且經常師大會發言人。現在他在UK做一個咨詢顧問。

    主站蜘蛛池模板: 国产成人精品亚洲日本在线| 我的小后妈韩剧在线看免费高清版 | 日韩免费一区二区三区| 国产做国产爱免费视频| 看Aⅴ免费毛片手机播放| 亚洲中字慕日产2020| 亚洲AV日韩精品久久久久久| 亚洲精品高清一二区久久| 日本成人在线免费观看| 一二三四在线观看免费高清中文在线观看| a国产成人免费视频| 免费一区二区三区在线视频 | 很黄很黄的网站免费的| 成全在线观看免费观看大全| 无码的免费不卡毛片视频| 亚洲国产综合AV在线观看| 亚洲日本在线观看网址| 亚洲国产一区二区三区青草影视| 亚洲色欲一区二区三区在线观看| 国产人成免费视频| 国产精品另类激情久久久免费| 毛片免费视频播放| 皇色在线视频免费网站| 午夜免费1000部| 免费在线观看视频网站| 四虎免费影院ww4164h| 2020因为爱你带字幕免费观看全集| 久久99毛片免费观看不卡| 亚洲高清免费视频| www免费黄色网| 国产一区二区三区免费观在线| 国产黄色片免费看| 两个人的视频www免费| 久久成人永久免费播放| 91视频免费网站| 美女被cao网站免费看在线看| 99免费在线视频| 亚在线观看免费视频入口| 国产精品免费无遮挡无码永久视频 | 永久免费av无码入口国语片| 两个人看的www免费视频中文|