<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
       ::  ::  :: 聯(lián)系 :: 聚合  :: 管理
    轉(zhuǎn)載地址:?
    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
    校對(duì):taowen

    關(guān)于Spring Framework,今年夏天你可能已經(jīng)聽見很多的議論。在本文中,我將試圖解釋Spring能完成什么,和我怎么會(huì)認(rèn)為它能幫助你開發(fā)J2EE應(yīng)用程序。

    又來一個(gè)framework?

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

    我相信Spring是獨(dú)特的,有幾個(gè)原因:


      它關(guān)注的領(lǐng)域是其他許多流行的Framework未曾關(guān)注的。Spring要提供的是一種管理你的業(yè)務(wù)對(duì)象的方法。

      Spring既是全面的又是模塊化的。Spring有分層的體系結(jié)構(gòu),這意味著你能選擇僅僅使用它任何一個(gè)獨(dú)立的部分,而它的架構(gòu)又是內(nèi)部一致。因此你能從你的學(xué)習(xí)中,得到最大的價(jià)值。例如,你可能選擇僅僅使用Spring來簡單化JDBC的使用,或用來管理所有的業(yè)務(wù)對(duì)象。

      它的設(shè)計(jì)從一開始就是要幫助你編寫易于測試的代碼。Spring是使用測試驅(qū)動(dòng)開發(fā)的工程的理想框架。

    Spring不會(huì)給你的工程添加對(duì)其他的框架依賴。Spring也許稱得上是個(gè)一站式解決方案,提供了一個(gè)典型應(yīng)用所需要的大部分基礎(chǔ)架構(gòu)。它還涉及到了其他framework沒有考慮到的內(nèi)容。

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

    2003年1月,Spring已經(jīng)落戶于SourceForge上了?,F(xiàn)在有10個(gè)開發(fā)人員,其中6個(gè)是高度投入的積極分子。

    Spring架構(gòu)上的好處

    在我們進(jìn)入細(xì)節(jié)之前,讓我們來看看Spring能夠給工程帶來的種種好處:


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

      Spring能消除在許多工程中常見的對(duì)Singleton的過多使用。根據(jù)我的經(jīng)驗(yàn),這是一個(gè)很大的問題,它降低了系統(tǒng)的可測試性和面向?qū)ο蟮某潭取?

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

      通過把對(duì)接口編程而不是對(duì)類編程的代價(jià)幾乎減少到?jīng)]有,Spring能夠促進(jìn)養(yǎng)成好的編程習(xí)慣。

      Spring被設(shè)計(jì)為讓使用它創(chuàng)建的應(yīng)用盡可能少的依賴于他的APIs。在Spring應(yīng)用中的大多數(shù)業(yè)務(wù)對(duì)象沒有依賴于Spring。

      使用Spring構(gòu)建的應(yīng)用程序易于單元測試。

      Spring能使EJB的使用成為一個(gè)實(shí)現(xiàn)選擇,而不是應(yīng)用架構(gòu)的必然選擇。你能選擇用POJOs或local EJBs來實(shí)現(xiàn)業(yè)務(wù)接口,卻不會(huì)影響調(diào)用代碼。

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

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

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

    Spring做了些什么?

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

    任務(wù)描述

    首先,讓我們明確Spring范圍。盡管Spring覆蓋了許多方面,但我們對(duì)它應(yīng)該涉什么,什么不應(yīng)該涉及有清楚的認(rèn)識(shí)。

    Spring的主要目的是使J2EE易用和促進(jìn)好編程習(xí)慣。

    Spring不重新輪子。因此,你發(fā)現(xiàn)在Spring中沒有l(wèi)ogging,沒有連接池,沒有分布式事務(wù)調(diào)度。所有這些東西均有開源項(xiàng)目提供(例如我們用于處理所有日志輸出的Commons Logging以及Commons DBCP),或由你的應(yīng)用程序服務(wù)器提供了。出于同樣的的原因,我們沒有提供O/R mapping層。對(duì)于這個(gè)問題已經(jīng)有了像Hibernate和JDO這樣的優(yōu)秀解決方案。

    Spring的目標(biāo)就是讓已有的技術(shù)更加易用。例如,盡管我們沒有底層事務(wù)協(xié)調(diào)處理,但我們提供了一個(gè)抽象層覆蓋了JTA或任何其他的事務(wù)策略。

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

    Spring也得益于內(nèi)在的一致性。所有的開發(fā)者都在唱同樣的的贊歌,基礎(chǔ)想法依然與Expert One-on-One J2EE設(shè)計(jì)與開發(fā)中提出的差不多。 并且我們已經(jīng)能夠在多個(gè)領(lǐng)域中使用一些中心的概念,例如Inversion of Control。

    Spring在應(yīng)用服務(wù)器之間是可移植的。當(dāng)然保證可移植性總是一種挑戰(zhàn),但是我們避免使用任何平臺(tái)特有或非標(biāo)準(zhǔn)的東西,并且支持在WebLogic,Tomcat,Resin,JBoss,WebSphere和其他的應(yīng)用服務(wù)器上的用戶。

    Inversion of Control 容器

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

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

    Bean factories 支持兩種模式的對(duì)象:


      Singleton:在此模式中,有一個(gè)具有特定名稱的共享對(duì)象實(shí)例,它在查找時(shí)被獲取。這是默認(rèn)的,而且是最為經(jīng)常使用的。它對(duì)于無狀態(tài)對(duì)象是一種理想的模式。

      Prototype:在此模式中,每次獲取將創(chuàng)建一個(gè)獨(dú)立的對(duì)象。例如,這可以被用于讓用戶擁有他們自己的對(duì)象。


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


      XmlBeanFactory: 可解析簡單直觀的定義類和命名對(duì)象屬性的XML結(jié)構(gòu)。 我們提供了一個(gè)DTD來使編寫更容易。

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

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

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

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

    通過BeanFactory概念,Spring成為一個(gè)Inversion of Control的容器。(我不怎么喜歡container這個(gè)詞,因?yàn)樗谷寺?lián)想到重量級(jí)容器,如EJB容器。Spring的BeanFactory是一個(gè)可通過一行代碼創(chuàng)建的容器,并且不需要特殊的部署步驟。)

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

    IoC有幾個(gè)重要的好處,例如:


      因?yàn)榻M件不需要在運(yùn)行時(shí)間尋找合作者,所以他們可以更簡單的編寫和維護(hù)。在Spring版的IoC里,組件通過暴露JavaBean的setter方法表達(dá)他們依賴的其他組件。這相當(dāng)于EJB通過JNDI來查找,EJB查找需要開發(fā)人員編寫代碼。

      同樣原因,應(yīng)用代碼更容易測試。JavaBean屬性是簡單的,屬于Java核心的,并且是容易測試的:僅編寫一個(gè)自包含的Junit測試方法用來創(chuàng)建對(duì)象和設(shè)置相關(guān)屬性即可。

      一個(gè)好的IoC實(shí)現(xiàn)保留了強(qiáng)類型。如果你需要使用一個(gè)通用的factory來尋找合作者,你必須通過類型轉(zhuǎn)換將返回結(jié)果轉(zhuǎn)變?yōu)橄胍念愋?。這不是一個(gè)大不了的問題,但是不雅觀。使用IoC,你在你的代碼中表達(dá)了強(qiáng)類型依賴,框架將負(fù)責(zé)類型轉(zhuǎn)換。這意味著在框架配置應(yīng)用時(shí),類型不匹配將導(dǎo)致錯(cuò)誤;在你的代碼中,你無需擔(dān)心類型轉(zhuǎn)換異常。

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

    最后應(yīng)該強(qiáng)調(diào)的是,IoC 不同于傳統(tǒng)的容器的體系結(jié)構(gòu),如EJB,應(yīng)用代碼最小程度地依靠于容器。這意味著你的業(yè)務(wù)對(duì)象可以潛在的被運(yùn)行在不同的IoC 框架上——或者在任何框架之外——不需要任何代碼的改動(dòng)。

    以我和其他Spring用戶的經(jīng)驗(yàn)來說,再怎么強(qiáng)調(diào)IoC給應(yīng)用程序代碼帶來的好處也不為過。

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

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

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

    對(duì)應(yīng)用開發(fā)人員,最重要的是,一個(gè)或多個(gè)BeanFactory提供了一個(gè)定義明確的業(yè)務(wù)對(duì)象層。這類似于local session bean層,但比它更簡單。與EJBs不同,在這個(gè)層中的對(duì)象可能是相關(guān)的,并且他們的關(guān)系被擁有它們的factory管理。有一個(gè)定義明確的業(yè)務(wù)對(duì)象層對(duì)于成功的體系結(jié)構(gòu)是非常重要的。

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


      信息查找,支持著國際化

      事件機(jī)制,允許發(fā)布應(yīng)用對(duì)象以及可選的注冊以接收到事件

      可移植的文件和資源訪問

    XmlBeanFactory 例子

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

    讓我們來看一個(gè)簡單的例子,它配置了三個(gè)應(yīng)用程序?qū)ο?,之間的關(guān)系在J2EE應(yīng)用中常常能夠看到:


      J2EE DataSource

      使用DataSource的DAO

      在處理過程中使用DAO的業(yè)務(wù)對(duì)象

    在下面的例子中,我們使用一個(gè)來自Jakarta Commons DBCP項(xiàng)目的BasicDataSource。這個(gè)class(和其他許多已有的class一樣)可以簡單地被應(yīng)用在Spring bean factory中,只要它提供了JavaBean格式的配置。需要在shutdown時(shí)被調(diào)用的Close方法可通過Spring的"destroy-method"屬性被注冊,以避免BasicDataSource需要實(shí)現(xiàn)任何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使用標(biāo)準(zhǔn)的 JavaBean屬性編輯器機(jī)制來把String轉(zhuǎn)換為其他的類型。

    現(xiàn)在,我們定義DAO,它有一個(gè)對(duì)DataSource的bean引用。Bean間關(guān)系通過<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>


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

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

    java代碼:?

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

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



    使用這個(gè)特性,Spring會(huì)找出exampleBusinessObject的dataSource屬性應(yīng)該被設(shè)置為在當(dāng)前BeanFactory中找到的DataSource實(shí)現(xiàn)。在當(dāng)前的BeanFactory中,如果所需要類型的bean不存在或多于一個(gè),將產(chǎn)生一個(gè)錯(cuò)誤。我們依然要設(shè)置exampleParam屬性,因?yàn)樗皇且粋€(gè)引用。

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

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

    現(xiàn)在讓我們來看看例子中業(yè)務(wù)對(duì)象的java 代碼。注意下面列出的代碼中沒有對(duì)Spring的依賴。不像EJB容器,Spring BeanFactory不具有侵入性:在應(yīng)用對(duì)象里面你通常不需要對(duì)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,它們對(duì)應(yīng)于bean定義文檔中的XML引用。這些將在對(duì)象被使用之前由Spring調(diào)用。

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

    注意在業(yè)務(wù)接口中沒有聲明將會(huì)一起使用的JavaBean屬性。 他們是一個(gè)實(shí)現(xiàn)細(xì)節(jié)。我們可以“插入”帶有不同bean屬性的不同的實(shí)現(xiàn)類而不影響連接著的對(duì)象或者調(diào)用的代碼。

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

    Bean factories 和application contexts 通常和J2EE server定義的一個(gè)范圍相關(guān)聯(lián),例如:


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

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

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

    這些J2EE規(guī)范提供的hook通常避免了使用Singleton來創(chuàng)造一個(gè)bean factory。

    然而,如果我們愿意的話可以用代碼創(chuàng)建一個(gè)BeanFactory,雖然是沒有什么意義的。例如,我們在以下三行代碼中可以創(chuàng)建bean factory并且得到一個(gè)業(yè)務(wù)對(duì)象的引用:

    java代碼:?

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



    這段代碼將能工作在一個(gè)應(yīng)用服務(wù)器之外:甚至不依賴J2EE,因?yàn)镾pring 的IoC容器是純java的。


    JDBC 抽象和數(shù)據(jù)存儲(chǔ)異常層次

    數(shù)據(jù)訪問是Spring 的另一個(gè)閃光點(diǎn)。

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

      需要冗長的錯(cuò)誤處理代碼來確保ResultSets,Statements以及(最重要的)Connections在使用后關(guān)閉。這意味著對(duì)JDBC的正確使用可以快速地導(dǎo)致大量的代碼量。它還是一個(gè)常見的錯(cuò)誤來源。Connection leak可以在有負(fù)載的情況下快速宕掉應(yīng)用程序。

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

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

      提供API,把冗長乏味和容易出錯(cuò)的異常處理從程序代碼移到框架之中??蚣芴幚硭械漠惓L幚?;程序代碼能夠集中精力于編寫恰當(dāng)?shù)腟QL和提取結(jié)果上。

      為你本要處理SQLException程序代碼提供有意義的異常層次。當(dāng)Spring第一次從數(shù)據(jù)源取得一個(gè)連接時(shí),它檢查元數(shù)據(jù)以確定數(shù)據(jù)庫。它使用這些信息把SQLException映射為自己從org.springframework.dao.DataAccessException派生下來的類層次中正確的異常。因而你的代碼可以與有意義的異常打交道,并且不需要為私有的SQLState或者錯(cuò)誤碼擔(dān)心。Spring的數(shù)據(jù)訪問異常不是JDBC特有的,因而你的DAO并不一定會(huì)因?yàn)樗鼈兛赡軖伋龅漠惓6壦涝贘DBC上。

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

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

    例如,Spring的JdbcTemplate對(duì)象能夠用于執(zhí)行SQL查詢并且在如下的列表中保存結(jié)果:

    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));
    ? ? ? ? ? ? ? ? }
    ? ? ? ? });



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

    JdbcTemplate提供許多支持不同情景包括prepared statements和批量更新的方法。Spring的JDBC抽象有比起標(biāo)準(zhǔn)JDBC來說性能損失非常小,甚至在當(dāng)應(yīng)用中需要的結(jié)果集數(shù)量很大的時(shí)候。

    在org.springframework.jdbc.object包中是對(duì)JDBC的更高層次的抽象。這是建立在核心的JDBC回調(diào)功能基礎(chǔ)紙上的,但是提供了一個(gè)能夠?qū)DBMS操作——無論是查詢,更新或者是存儲(chǔ)過程——使用Java對(duì)象來建模的API。這個(gè)API部分是受到JDO查詢API的影響,我發(fā)現(xiàn)它直觀而且非常有用。

    一個(gè)用于返回User對(duì)象的查詢對(duì)象可能是這樣的:

    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);
    ? ? ? ? }
    }


    這個(gè)類可以在下面用上:
    java代碼:?


    User user = userQuery.findUser(25);


    這樣的對(duì)象經(jīng)??梢杂米鱀AO的inner class。它們是線程安全的,除非子類作了一些超出常規(guī)的事情。

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

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

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

    注意如果我們確實(shí)需要從unchecked數(shù)據(jù)訪問異常中恢復(fù),我們?nèi)匀豢梢赃@么做。我們可以編寫代碼僅僅處理可恢復(fù)的情況。例如,如果我們認(rèn)為只有optimistic locking violation是可恢復(fù)的,我們可以在Spring的DAO中如下這么寫:

    java代碼:?


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


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


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


    第一個(gè)例子的潛在缺陷是——編譯器不能強(qiáng)制處理可能的可恢復(fù)的異?!@對(duì)于第二個(gè)也是如此。因?yàn)槲覀儽粡?qiáng)制捕捉base exception(DataAccessException),編譯器不會(huì)強(qiáng)制對(duì)子類(OptimisticLockingFailureException)的檢查。因而編譯器可能強(qiáng)制我們編寫處理不可恢復(fù)問題的代碼,但是對(duì)于強(qiáng)制我們處理可恢復(fù)的問題并未有任何幫助。

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

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


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

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

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

      無論使用的是什么持久化技術(shù),你都會(huì)發(fā)現(xiàn)容易實(shí)現(xiàn)DAO模式,讓業(yè)務(wù)代碼無需依賴于任何特定的數(shù)據(jù)訪問API。

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

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

    O/R mapping 集成

    當(dāng)然你經(jīng)常需要使用O/R mapping,而不是使用關(guān)系數(shù)據(jù)訪問。你總體的應(yīng)用程序框架也必須支持它。因而提供了對(duì)Hibernate 2.x和JDO的集成支持。它的數(shù)據(jù)訪問架構(gòu)使得它能和任何底層的數(shù)據(jù)訪問技術(shù)集成。Spring和Hibernate集成得尤其好。

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


      Session 管理 Spring提供有效率的,簡單的以并且是安全的處理Hibernate Session。使用Hibernate的相關(guān)代碼為了效率和恰當(dāng)?shù)氖聞?wù)處理一般需要使用相同的Hibernate “Session”對(duì)象。Spring讓它容易透明地創(chuàng)建和綁定Session到當(dāng)前的線程,要么使用聲明式,AOP的method interceptor方法,要么在Java代碼層面使用顯式的,“template”包裝類。因而Spring解決了在Hibernate論壇上經(jīng)常出現(xiàn)的用法問題。

      資源管理 Spring的應(yīng)用程序context能夠處理Hiberante SessionFactories的位置和配置,JDBC數(shù)據(jù)源和其他相關(guān)資源。這使得這些值易于管理和改變。

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

      如上描述的異常包裝 Spring能夠包裝Hibernate異常,把它們從私有的,checked異常轉(zhuǎn)換為一套抽象的運(yùn)行時(shí)異常。這使得你能夠僅僅在恰當(dāng)?shù)膶用嫣幚泶蟛糠植豢苫謴?fù)的持久化異常,而不影響樣板catch/throw,和異常聲明。你仍然能夠在任何你需要的地方捕捉和處理異常。記住JDBC異常(包括DB特有的方言)也被轉(zhuǎn)換到相同的層次中,意味著你能在一致的編程模型中對(duì)JDBC執(zhí)行相同的操作。

      為了避免和廠商綁定 Hibernate是強(qiáng)大的,靈活的,開放源代碼并且免費(fèi),但是它仍然使用私有的API。給出了一些選擇,使用標(biāo)準(zhǔn)或者抽象API實(shí)現(xiàn)主要的程序功能通常是你想要的,當(dāng)你需要因?yàn)楣δ?,性能,或者其他考慮要轉(zhuǎn)換到使用其他實(shí)現(xiàn)時(shí)。

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

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

      Spring提供了它自己對(duì)事務(wù)管理的抽象。Spring提供了這些:


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

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

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

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

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

      AOP

      最近在應(yīng)用AOP來解決企業(yè)關(guān)注點(diǎn)方面大家有了很大的興趣,例如事務(wù)管理,這些都是EJB所要解決的。

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

      Spring AOP支持method interception。所支持關(guān)鍵的AOP概念包括:


        Interception:自定義行為能夠在對(duì)接口和類的調(diào)用之前和之后插入。這類似于AspectJ術(shù)語中類似的“around advice”。

        Introduction:指定advice會(huì)導(dǎo)致對(duì)象實(shí)現(xiàn)額外的接口。這混亂了繼承。

        靜態(tài)和動(dòng)態(tài)的pointcuts:在interception發(fā)生的程序執(zhí)行處指定points。靜態(tài)pointcuts concern函數(shù)簽名;動(dòng)態(tài)pointcuts也可以在point被求值的地方考慮函數(shù)的參數(shù)。Pointcuts獨(dú)立interceptors單獨(dú)定義,使得標(biāo)準(zhǔn)interceptor可以應(yīng)用于不同應(yīng)用程序和代碼上下文。

      Spring既支持有狀態(tài)(一個(gè)advised對(duì)象一個(gè)實(shí)例)也支持無狀態(tài)的interceptors(所有advice使用一個(gè)實(shí)例)。

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

      Spring使用動(dòng)態(tài)代理實(shí)現(xiàn)AOP(其中存在一個(gè)接口)或者在運(yùn)行時(shí)使用CGLIB生成字節(jié)碼(這使得能夠代理類)。兩種方法都能夠在任何應(yīng)用服務(wù)器中使用。

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

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

      因?yàn)镾pring在實(shí)例上advises 對(duì)象,而不是在class loader層面上,使用有不同advice的同一個(gè)類的多個(gè)實(shí)例是可能的,或者與advised實(shí)例一道使用unadvised 實(shí)例。

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

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


        事務(wù)管理能夠應(yīng)用于任何POJO。我們推薦業(yè)務(wù)對(duì)象實(shí)現(xiàn)接口,但是這只是一個(gè)好的編程習(xí)慣的問題,而不是由框架強(qiáng)制的。

        通過使用Spring的事務(wù)API能夠在事務(wù)性POJO中實(shí)現(xiàn)編程回調(diào)。我們?yōu)榇颂峁╈o態(tài)的方法,使用ThreadLoacal變量,因而你不需要傳播諸如EJBContext這樣的context對(duì)象來確?;貪L。

        你可以聲明式地定義“回滾規(guī)則”。EJB不會(huì)在未捕捉程序異常的時(shí)候自動(dòng)回滾(僅僅在unchecked exceptions和其他Throwables的時(shí)候),應(yīng)用程序開發(fā)者經(jīng)常需要在任何異常發(fā)生時(shí)回滾。Spring事務(wù)管理讓你能夠聲明式地指定什么異常什么子類能夠?qū)е伦詣?dòng)回滾。缺省的行為和EJB是一致的,但是你能夠在checked和unchecked異常時(shí)自動(dòng)回滾。這個(gè)在最少化自編程回調(diào)代碼方面有很大好處,而回調(diào)依賴于Spring的事務(wù)API(因?yàn)镋JB的編程回調(diào)時(shí)在EJBContext中完成的)。

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

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


        自定義的security interception,當(dāng)安全檢查的復(fù)雜度超出了J2EE安全架構(gòu)的能力的時(shí)候

        在開發(fā)中使用的調(diào)試和profiling aspects

        發(fā)送email通知管理員用戶不尋常的舉動(dòng)的Interceptors

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

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

      下面的XML片斷展示了如何定義一個(gè)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()方法返回時(shí)依賴的是代理接口。(多個(gè)代理方法是被支持的。)ProxyFactoryBean的“interceptorNames”屬性需要一個(gè)字符串列表。(因?yàn)槿绻硎且粋€(gè)“prototype”而不是singleton,有狀態(tài)interceptors可能需要?jiǎng)?chuàng)建新的實(shí)例,所以必須使用Bean的名字而不是bean的引用。)列表中的名字可以是interceptor或者pointcuts(interceptors和有關(guān)它們合適被使用的信息)。列表中的“target”值自動(dòng)創(chuàng)建一個(gè)“invoker interceptor”封裝target對(duì)象。實(shí)現(xiàn)代理接口的是在factory中的bean的名字。這個(gè)例子中的myTest可以和其他bean factory中的bean一樣使用。例如,其他對(duì)象可以使用<ref>元素引用它而且這些引用是由Spring IoC設(shè)置的。

      還可以不用BeanFactory,編程構(gòu)建AOP代理,雖然這個(gè)很少用得上:

      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的替代無提供企業(yè)服務(wù)這個(gè)用法方面的進(jìn)步是重要的。隨著時(shí)間,這將成為Spring很重要的關(guān)注點(diǎn)。

      MVC web 框架

      Spring包括一個(gè)強(qiáng)大而且高度可配置的MVC web 框架。

      Spring的MVC model類似于Struts。在多線程服務(wù)對(duì)象這點(diǎn)上,Spring的Controller類似于Struts Action,只有一個(gè)實(shí)例處理所有客戶的請求。然而,我們相信Spring的MVC比起Struts有很多優(yōu)點(diǎn),例如:


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

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

        Spring MVC是真正的view無關(guān)的。你不會(huì)被強(qiáng)制使用JSP,如果你不想那么做的話。你可以使用Velocity,XSLT或其他view技術(shù)。如果你想要使用自定義的view機(jī)制——例如,你自己的模板語言——你可以簡單實(shí)現(xiàn)Spring的View接口并且把它集成進(jìn)來。

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

        Web層變成了業(yè)務(wù)對(duì)象層之上的薄薄一層。這鼓勵(lì)了好的習(xí)慣。Struts和其他專門的web框架讓你去實(shí)現(xiàn)你自己的業(yè)務(wù)對(duì)象;Spring提供了你應(yīng)用程序所有層的集成。

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

      下面的例子展示了一個(gè)簡單的Spring Controller如何能夠訪問定義在應(yīng)用程序context中的業(yè)務(wù)對(duì)象。這個(gè)controller在它的handleRequest()方法中執(zhí)行了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是一個(gè)GLUE web services代理,由Spring FActoryBean返回。然而,Spring把controller從底層web service庫中分離出來。接口可以使用普通的Java對(duì)象,test stub,mock對(duì)象或者如下面要討論的EJB代理實(shí)現(xiàn)。這個(gè)contorller不包括資源查找;除了支持它的web交互的必要代碼之外沒有別的什么了。

      Spring還提供了數(shù)據(jù)綁定,forms,wizards和更復(fù)雜的工作流的支持。

      對(duì)Spring MVC 框架的優(yōu)秀簡介是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的分層架構(gòu)使得你能夠使用Spring的其他部分而不用MVC層。我們有使用Spring做中間層管理和數(shù)據(jù)訪問,但是在web層使用Struts,WebWork或者Tapestry的用戶。

      實(shí)現(xiàn)EJB

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

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

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

      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是一個(gè)接口,它的實(shí)現(xiàn)類——以及任何它需要的配置,注入基本的屬性和更多的合作者——在XML bean factory 定義中隱藏。

      我們通過在ejb-jar.xmldeployment descriptor中名為ejb/BeanFactoryPath的環(huán)境變量定義告訴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 文件將會(huì)從classpath裝載:在本例中,是EJB Jar文件的根目錄。每個(gè)EJB都能指定自己的XML文檔,因而這個(gè)機(jī)制能在每個(gè)EJB Jar文件中使用多次。

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

      使用EJB

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


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

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

        實(shí)現(xiàn)Business Delegate模式通常導(dǎo)致顯著的代碼重復(fù),其中我們必須編寫大量僅僅是調(diào)用EJB同等方法的方法。

      基于這些和其他原因,傳統(tǒng)的EJB訪問,如在Sun Adventure Builder和OTN J2EE Virtual Shopping Mall中展示的那樣,會(huì)降低生產(chǎn)率并且?guī)盹@著的復(fù)雜度。

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

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

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

      java代碼:?


      private MyComponent myComponent;

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


      我們隨后在任何業(yè)務(wù)方法中使用這個(gè)實(shí)例變量。

      Spring自動(dòng)完稱剩下的工作,通過像這樣的XML bean定義。LocalStatelessSessionProxyFactoryBean是一個(gè)可以用于任何EJB的通用factory bean。它創(chuàng)建的對(duì)象能夠自動(dòng)被Spring轉(zhuǎn)型為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>


      在幕后有許多魔法般的事情發(fā)生,Spring AOP framework的殷勤,雖然不強(qiáng)迫你使用AOP的概念享受這些結(jié)果。“myComponent”bean定義為EJB創(chuàng)建一個(gè)代理,它實(shí)現(xiàn)了業(yè)務(wù)方法的接口。EJB local home在啟動(dòng)的時(shí)候被緩存,因而只需要一次JNDI查找。每次EJB被調(diào)用的時(shí)候,代理調(diào)用local EJB中的create()方法并且調(diào)用EJB中對(duì)應(yīng)的業(yè)務(wù)方法。

      myController bean定義為這個(gè)代理設(shè)置controller類的myController屬性。

      這個(gè)EJB訪問機(jī)制極大簡化了應(yīng)用程序的代碼:


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

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

      在實(shí)際程序中的性能測試和經(jīng)驗(yàn)標(biāo)明這種方法(包括對(duì)目標(biāo)EJB的反射調(diào)用)的性能影響是很小的,在典型的應(yīng)用中檢測不出。記住無論如何我們都不希望使用fine-grained的EJB調(diào)用,因?yàn)闀?huì)有有關(guān)應(yīng)用服務(wù)器上的EJB的底層架構(gòu)方面的代價(jià)。

      我們可以把相同方法應(yīng)用于遠(yuǎn)程EJB,通過類似org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean factory bean的方法。然而我們無法隱藏遠(yuǎn)程EJB的業(yè)務(wù)方法接口中的RemoteException。

      測試

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

      Spring自身有一個(gè)極好的單元測試包。我們的1.0 M1的單元測試覆蓋率是75%,而且我們希望在1.0 RC1的時(shí)候能夠達(dá)到80%的單元測試覆蓋率。我們發(fā)現(xiàn)在這個(gè)項(xiàng)目中測試優(yōu)先的開發(fā)帶來的好處是實(shí)實(shí)在在的。例如,它使得作為國際化分布式開發(fā)團(tuán)隊(duì)的工作極端有效率,而且用戶評(píng)論CVS snapshots趨向于穩(wěn)定和使用安全。

      因?yàn)橐韵吕碛?,我們相信用Spring構(gòu)建的應(yīng)用程序是非常易于測試的:


        IoC推動(dòng)了單元測試

        應(yīng)用程序不包括直接使用注入JNDI的J2EE服務(wù)的plumbing code,這些代碼一般讓測試難于進(jìn)行

        Spring bean factories和contexts能夠在容器外設(shè)置

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

      誰在使用Spring

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

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

      Roadmap

      在今年晚些時(shí)候我們主要要做的是讓Spring發(fā)布release 1.0。然而,我們還有一些更長遠(yuǎn)的目標(biāo)。

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

      1.0之后,一些可能的改進(jìn)地方包括:


        通過對(duì)我們的JDBC和事務(wù)支持的一個(gè)相當(dāng)抽象來支持JMS

        支持bean factories的動(dòng)態(tài)重配置

        提供web services的能力

        IDE和其他工具支持

      作為一個(gè)敏捷項(xiàng)目,我們主要是受到用戶需求的驅(qū)動(dòng)。因而我們不會(huì)開發(fā)沒有一個(gè)用戶需要的特性,并且我們會(huì)仔細(xì)傾聽來自用戶群的聲音。

      總結(jié)

      Spring是一個(gè)解決了許多在J2EE開發(fā)中常見的問題的強(qiáng)大框架。

      Spring提供了管理業(yè)務(wù)對(duì)象的一致方法并且鼓勵(lì)了注入對(duì)接口編程而不是對(duì)類編程的良好習(xí)慣。Spring的架構(gòu)基礎(chǔ)是基于使用JavaBean屬性的Inversion of Control容器。然而,這僅僅是完整圖景中的一部分:Spring在使用IoC容器作為構(gòu)建完關(guān)注所有架構(gòu)層的完整解決方案方面是獨(dú)一無二的。

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

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

      Spring提供了一個(gè)用標(biāo)準(zhǔn)Java語言編寫的AOP框架,它給POJOs提供了聲明式的事務(wù)管理和其他企業(yè)事務(wù)——如果你需要——還能實(shí)現(xiàn)你自己的aspects。這個(gè)框架足夠強(qiáng)大,使得應(yīng)用程序能夠拋開EJB的復(fù)雜性,同時(shí)享受著和傳統(tǒng)EJB相關(guān)的關(guān)鍵服務(wù)。

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


      更多信息

      參見以下資源獲得關(guān)于Spring的更多信息:


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

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

        在Sourceforge上的論壇和下載

        Spring用戶和Spring開發(fā)者的郵件列表

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

      關(guān)于作者

      Rod Johnson 作為Java開發(fā)者和架構(gòu)師已經(jīng)有了7年的經(jīng)驗(yàn)了并且在J2EE平臺(tái)出現(xiàn)之初就在其上進(jìn)行開發(fā)了。他是《Expert One-on-One J2EE Design and Development》(Wrox,2002)的作者并且貢獻(xiàn)了其他好幾本關(guān)于J2EE的書。他當(dāng)前正在為Wiley撰寫另外一本有關(guān)J2EE架構(gòu)的書。Rod在兩個(gè)Java標(biāo)準(zhǔn)委員會(huì)服務(wù)并且經(jīng)常師大會(huì)發(fā)言人。現(xiàn)在他在UK做一個(gè)咨詢顧問。

    主站蜘蛛池模板: 亚洲午夜精品在线| 美女一级毛片免费观看| 国产亚洲精品拍拍拍拍拍| 亚洲美女视频免费| 色www永久免费网站| 无码日韩人妻av一区免费| 亚洲一区二区三区精品视频| 亚洲免费观看视频| 亚洲成a人片在线观看久| 巨胸喷奶水视频www网免费| 亚洲欧美日韩中文高清www777| 亚洲AV无码1区2区久久| 全免费一级毛片在线播放| 13一14周岁毛片免费| 九九精品成人免费国产片| 国产日韩在线视频免费播放| 国产成人综合亚洲一区| 亚洲爆乳少妇无码激情| 国产成人亚洲综合一区| 亚洲国产日韩在线观频| 国产色婷婷精品免费视频| 两个人看www免费视频| 日韩免费在线中文字幕| 美美女高清毛片视频黄的一免费| 亚洲欧美成人av在线观看| 亚洲国产成人精品久久| 亚洲精品91在线| 亚洲精品白色在线发布| 亚洲精品美女视频| 亚洲日本在线播放| 亚洲福利一区二区精品秒拍| 18亚洲男同志videos网站| 亚洲黄网在线观看| 亚洲日韩在线视频| 亚洲乱码一二三四区麻豆| 亚洲国产成人精品激情| 亚洲日韩av无码中文| 亚洲国产午夜精品理论片在线播放| 亚洲欧美aⅴ在线资源| 亚洲爆乳大丰满无码专区| 亚洲精品无码专区久久|