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 的接口。

代碼:
<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>元素來指定:

代碼:
<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特性:

代碼:
<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的存在硬編碼。

代碼:
public class ExampleBusinessObject implements MyBusinessObject {

   private ExampleDataAccessObject dao;
   private int exampleParam;

   public void setDataAccessObject(ExampleDataAccessObject dao) {
      this.dao = dao;
   }

   public void setExampleParam(int exampleParam) {
      this.exampleParam = exampleParam;
   }

   public void 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並且得到一個業務對象的引用:

代碼:
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查詢並且在如下的列表中保存結果:

代碼:
JdbcTemplate template = new JdbcTemplate(dataSource);
final List names = new LinkedList();
template.query("SELECT USER.NAME FROM USER",
   new RowCallbackHandler() {
      public void processRow(ResultSet rs) throws SQLException {
         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對象的查詢對象可能是這樣的:

代碼:

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
   protected Object mapRow(ResultSet rs, int rownum) throws SQLException {
      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);
   }
}

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

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中如下這麼寫:

代碼:

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

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

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代理:

代碼:

<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代理,雖然這個很少用得上:

代碼:

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搜索:

代碼:

public class GoogleSearchController
      implements Controller {

   private IGoogleSearchPort google;

   private String googleKey;

   public void setGoogle(IGoogleSearchPort google) {
      this.google = google;
   }

   public void 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);

      return new 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可以這麼獲得和使用所需對象:

代碼:

import org.springframework.ejb.support.AbstractStatelessSessionBean;

public class MyEJB extends AbstractStatelessSessionBean
         implements MyBusinessInterface {
   private MyPOJO myPOJO;

   protected void onEjbCreate() {
      this.myPOJO = getBeanFactory().getBean("myPOJO");
   }

   public void myBusinessMethod() {
      this.myPOJO.invokeMethod();
   }
}

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

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

代碼:

<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方法。這將如下保存作爲實例變量的引用:

代碼:

private MyComponent myComponent;

public void setMyComponent(MyComponent myComponent) {
   this.myComponent = myComponent;
}

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

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

代碼:

<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做一個諮詢顧
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章