1. 程式人生 > >Spring官方文件翻譯(1~6章)

Spring官方文件翻譯(1~6章)

Spring框架是一個輕量級的解決方案,可以一站式地構建企業級應用。Spring是模組化的,所以可以只使用其中需要的部分。可以在任何web框架上使用控制反轉(IoC),也可以只使用Hibernate整合程式碼JDBC抽象層。它支援宣告式事務管理、通過RMI或web服務實現遠端訪問,並可以使用多種方式持久化資料。它提供了功能全面的MVC框架,可以透明地整合AOP到軟體中。

Spring被設計為非侵入式的,這意味著你的域邏輯程式碼通常不會依賴於框架本身。在整合層(比如資料訪問層),會存在一些依賴同時依賴於資料訪問技術和Spring,但是這些依賴可以很容易地從程式碼庫中分離出來。

本文件是Spring框架的參考指南,如果你有任何請求、評論或問題,

請給我們發郵件,關於框架本身的問題將在StackOverflow上討論(見https://spring.io.questions)。

這篇參考指南提供了Spring框架的詳細資訊,包括了對所有功能的全面理解,同時也包括一些重要概念的背景(比如,依賴注入)。

如果你才開始使用Spring,可以通過建立一個基於Spring Boot的應用開始使用Spring框架。Spring Boot提供了一種快速建立Spring應用的方式,它基於Spring框架,支援約定優於配置,使你可以儘快啟動並執行。

可以使用start.spring.io或遵循入門指南(比如,構建RESTful web應用入門)生成一個基本的專案。除了易於理解,這些指南聚集於一個個任務,它們大部分都是基於Spring Boot的,同時也包含了Spring包下的其它專案,以便你可以考慮何時使用它們解決特定的問題。

Spring框架是基於Java平臺的,它為開發Java應用提供了全方位的基礎設施支援,並且它很好地處理了這些基礎設施,所以你只需要關注你的應用本身即可。

Spring可以使用POJO(普通的Java物件,plain old java objects)建立應用,並且可以將企業服務非侵入式地應用到POJO。這項功能適用於Java SE程式設計模型以及全部或部分的Java EE。

那麼,做為開發者可以從Spring獲得哪些好處呢?

  • 不用關心事務API就可以執行資料庫事務;
  • 不用關心遠端API就可以使用遠端操作;
  • 不用關心JMX API就可以進行管理操作;
  • 不用關心JMS API就可以進行訊息處理。

譯者注:①JMX,Java Management eXtension,Java管理擴充套件,是一個為應用程式、裝置、系統等植入管理功能的框架。JMX可以跨越一系列異構作業系統平臺、系統體系結構和網路傳輸協議,靈活的開發無縫整合的系統、網路和服務管理應用。②JMS,Java Message Service,Java訊息服務,是Java平臺上有關面向訊息中介軟體(MOM)的技術規範,它便於訊息系統中的Java應用程式進行訊息交換,並且通過提供標準的產生、傳送、接收訊息的介面簡化企業應用的開發。

一個Java應用程式,從受限制的嵌入式應用到n層的服務端應用,典型地是由相互合作的物件組成的,因此,一個應用程式中的物件是相互依賴的。

Java平臺雖然提供了豐富的應用開發功能,但是它並沒有把這些基礎構建模組組織成連續的整體,而是把這項任務留給了架構師和開發者。你可以使用設計模式,比如工廠模式、抽象工廠模式、建立者模式、裝飾者模式以及服務定位器模式等,來構建各種各樣的類和物件例項,從而組成整個應用程式。這些設計模式是很簡單的,關鍵在於它們根據最佳實踐起了很好的名字,它們的名字可以很好地描述它們是幹什麼的、用於什麼地方、解決什麼問題,等等。這些設計模式都是最佳實踐的結晶,所以你應該在你的應用程式中使用它們。

Spring的控制反轉解決了上述問題,它提供了一種正式的解決方案,你可以把不相干元件組合在一起,從而組成一個完整的可以使用的應用。Spring根據設計模式編碼出了非常優秀的程式碼,所以可以直接整合到自己的應用中。因此,大量的組織機構都使用Spring來保證應用程式的健壯性和可維護性。

背景

2004年Martin Fowler在他的網站上提出了關於控制反轉(IoC,Inversion of Control)的問題,“The question is, what aspect of control are [they] inverting?”,後來,他又建議重新命名這項原則,使其可以自我解釋,從而提出了依賴注入(DI,Dependency Injection)的概念。

2.2 模組

Spring大約包含了20個模組,這些模組組成了核心容器(Core Container)、資料訪問/整合(Data Access/Integration)、Web、AOP(面向切面程式設計,Aspect Oriented Programming)、Instrumentation、訊息處理(Messaging)和測試(Test),如下圖:

圖 2.1. Spring框架概述
spring框架概述

下面列出了每項功能對應的模組及其主題,它們都有人性的名字(artifact name),這些名字與依賴管理工具中的 artifact id 是相互對應的。

核心容器包括spring-corespring-beansspring-contextspring-context-supportspring-expression(SpEL,Spring表示式語言,Spring Expression Language)等模組。

spring-corespring-beans模組是Spring框架的基礎,包括控制反轉和依賴注入等功能。BeanFactory是工廠模式的微妙實現,它移除了編碼式單例的需要,並且可以把配置和依賴從實際編碼邏輯中解耦。

Contextspring-context)模組是在Core和Bean模組的基礎上建立起來的,它以一種類似於JNDI註冊的方式訪問物件。Context模組繼承自Bean模組,並且添加了國際化(比如,使用資源束)、事件傳播、資源載入和透明地建立上下文(比如,通過Servelet容器)等功能。Context模組也支援Java EE的功能,比如EJB、JMX和遠端呼叫等。ApplicationContext介面是Context模組的焦點。spring-context-support提供了對第三方庫整合到Spring上下文的支援,比如快取(EhCache, Guava, JCache)、郵件(JavaMail)、排程(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。

spring-expression模組提供了強大的表示式語言用於在執行時查詢和操作物件圖。它是JSP2.1規範中定義的統一表達式語言的擴充套件,支援set和get屬性值、屬性賦值、方法呼叫、訪問陣列集合及索引的內容、邏輯算術運算、命名變數、通過名字從Spring IoC容器檢索物件,還支援列表的投影、選擇以及聚合等。

spring-aop模組提供了面向切面程式設計(AOP)的實現,可以定義諸如方法攔截器和切入點等,從而使實現功能的程式碼徹底的解耦出來。使用原始碼級的元資料,可以用類似於.Net屬性的方式合併行為資訊到程式碼中。

spring-aspects模組提供了對AspectJ的整合。

spring-instrument模組提供了對檢測類的支援和用於特定的應用伺服器的類載入器的實現。spring-instrument-tomcat模組包含了用於tomcat的Spring檢測代理。

Spring 4 包含的spring-messaging模組是從Spring整合專案的關鍵抽象中提取出來的,這些專案包括MessageMessageChannelMessageHandler和其它服務於訊息處理的專案。這個模組也包含一系列的註解用於對映訊息到方法,這類似於Spring MVC基於編碼模型的註解。

資料訪問與整合層包含JDBC、ORM、OXM、JMS和事務模組。
(譯者注:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service)

spring-jdbc模組提供了JDBC抽象層,它消除了冗長的JDBC編碼和對資料庫供應商特定錯誤程式碼的解析。

spring-tx模組支援程式設計式事務和宣告式事務,可用於實現了特定介面的類和所有的POJO物件。
(譯者注:程式設計式事務需要自己寫beginTransaction()、commit()、rollback()等事務管理方法,宣告式事務是通過註解或配置由spring自動處理,程式設計式事務粒度更細)

spring-orm模組提供了對流行的物件關係對映API的整合,包括JPAJDOHibernate等。通過此模組可以讓這些ORM框架和spring的其它功能整合,比如前面提及的事務管理。

spring-oxm模組提供了對OXM實現的支援,比如JAXB、Castor、XML Beans、JiBX、XStream等。

spring-jms模組包含生產(produce)和消費(consume)訊息的功能。從Spring 4.1開始,集成了spring-messaging模組。

Web層包括spring-webspring-webmvcspring-websocketspring-webmvc-portlet等模組。

spring-web模組提供面向web的基本功能和麵向web的應用上下文,比如多部分(multipart)檔案上傳功能、使用Servlet監聽器初始化IoC容器等。它還包括HTTP客戶端以及Spring遠端呼叫中與web相關的部分。

spring-webmvc模組(即Web-Servlet模組)為web應用提供了模型檢視控制(MVC)和REST Web服務的實現。Spring的MVC框架可以使領域模型程式碼和web表單完全地分離,且可以與Spring框架的其它所有功能進行整合。

spring-webmvc-portlet模組(即Web-Portlet模組)提供了用於Portlet環境的MVC實現,並反映了spring-webmvc模組的功能。

spring-test模組通過JUnit和TestNG元件支援單元測試整合測試。它提供了一致性地載入快取Spring上下文,也提供了用於單獨測試程式碼的模擬物件(mock object)。

前面提及的構建模組使得Spring在很多場景成為一種合理的選擇,不管是資源受限的嵌入式應用還是使用了事務管理和web整合框架的成熟的企業級應用。

圖2.2. 典型的成熟的Spring web應用程式
典型的成熟的Spring web應用程式

Spring的宣告式事務管理可以使web應用完成事務化,就像使用EJB容器管理的事務。所有客制的業務邏輯都可以使用簡單的POJO實現,並用Spring的IoC容器進行管理。另外,還包括髮郵件和驗證功能,其中驗證功能是從web層分離的,由你決定何處執行驗證。Spring的ORM可以整合JPA、Hibernate和JDO等,比如,使用Hibernate時,可以繼續使用已存在的對映檔案和標準的Hibernate的SessionFactory配置。表單控制器無縫地把web層和領域模型整合在一起,移除了ActionForms和其它把HTTP引數轉換成領域模型的類。

圖2.3. 使用第三方web框架的Spring中介軟體
使用第三方web框架的Spring中介軟體

一些場景可能不允許你完全切換到另一個框架。然而,Spring框架不強制你使用它所有的東西,它不是非此即彼(all-or-nothing)的解決方案。前端使用Struts、Tapestry、JSF或別的UI框架可以和Spring中介軟體整合,從而使用Spring的事務管理功能。僅僅只需要使用ApplicationContext連線業務邏輯,並使用WebApplicationContext整合web層即可。

圖2.4. 遠端呼叫使用場景
遠端呼叫使用場景

當需要通過web服務訪問現有程式碼時,可以使用Spring的Hessian-Burlap-Rmi-或者JaxRpcProxyFactory類,遠端訪問現有的應用並非難事。

圖2.5. EJB-包裝現有的POJO
EJB-包裝現有的POJO

Spring框架也為EJB提供了訪問抽象層,可以重新使用現有的POJO並把它們包裝到無狀態的會話bean中,以使其用於可擴充套件的安全的web應用中。

依賴管理和依賴注入是兩碼事。為了讓應用程式擁有這些Spring的非常棒的功能(如依賴注入),需要匯入所需的全部jar包,並在執行時放在classpath下,有可能的話編譯期也應該放在classpath下。這些依賴並不是被注入的虛擬元件,而是檔案系統上典型的物理資源。依賴管理的處理過程涉及到定位這些資源、儲存並新增它們到classpath下。依賴可能是直接的(比如執行時依賴於Spring),也可能是間接的(比如依賴於commons-dbcpcommons-dbcp又依賴於commons-pool)。間接的依賴又被稱作“傳遞”,它們是最難識別和管理的。

如果準備使用Spring,則需要拷貝一份所需模組的Spring的jar包。為了便於使用,Spring被打包成一系列的模組以儘可能地減少依賴,比如,如果不是在寫一個web應用,那就沒必要引入spring-web模組。這篇文件中涉及到的Spring模組,我們使用spring-*spring-*.jar的命名約定,其中,*代表模組的短名字(比如,spring-corespring-webmvcspring-jms等等)。實際使用的jar包正常情況下都是帶有版本號的(比如,spring-core-4.3.0.RELEASE.jar)。

每個版本的Spring都會在以下地方釋出artifact:

  • Maven中央倉庫,預設的Maven查詢倉庫,並且不需要特殊的配置就可以使用。許多Spring依賴的公共庫也可以從Maven中央倉庫獲得,並且大部分的Spring社群也使用Maven作為依賴管理工具,所以很方便。Maven中的jar包命名格式為spring-*-<version>.jar,其groupId是org.springframework。
  • 特別為託管Spring的公共的Maven倉庫。除了最終的GA版本,這個倉庫也託管了開發的快照版本和里程碑版本。jar包和Maven中央倉庫中的命名一致,所以這也是一個獲取Spring的開發版本的有用地方,可以和Maven中央倉庫中部署的其它庫一起使用。這個倉庫也包含了捆綁了所有Spring jar包的發行版的zip檔案,以便於下載。

因此,首先要做的事就是決定如何管理依賴關係,我們一般推薦使用自動管理的系統,比如Maven、Gradle或Ivy,當然你也可以手動下載所有的jar包。

下面列出了Spring的artifact,每個模組更完整的描述,參考 2.2 模組 章節。

表2.1. Spring框架的artifact

groupId artifactId 描述
org.springframework spring-aop 基於代理的AOP
org.springframework spring-aspects 基於切面的AspectJ
org.springframework spring-beans bean支援,包括Groovy
org.springframework spring-context 執行時上下文,包括排程和遠端呼叫抽象
org.springframework spring-context-support 包含用於整合第三方庫到Spring上下文的類
org.springframework spring-core 核心庫,被許多其它模組使用
org.springframework spring-expression Spring表示式語言
org.springframework spring-instrument JVM引導的檢測代理
org.springframework spring-instrument-tomcat tomcat的檢測代理
org.springframework spring-jdbc JDBC支援包,包括對資料來源設定和JDBC訪問支援
org.springframework spring-jms JMS支援包,包括髮送和接收JMS訊息的幫助類
org.springframework spring-messaging 訊息處理的架構和協議
org.springframework spring-orm 物件關係對映,包括對JPA和Hibernate支援
org.springframework spring-oxm 物件XML對映
org.springframework spring-test 單元測試和整合測試元件
org.springframework spring-tx 事務基礎,包括對DAO的支援及JCA的整合
org.springframework spring-web web支援包,包括客戶端及web遠端呼叫
org.springframework spring-webmvc REST web服務及web應用的MVC實現
org.springframework spring-webmvc-portlet 用於Portlet環境的MVC實現
org.springframework spring-websocket WebSocket和SockJS實現,包括對STOMP的支援

Spring對大部分企業和其它外部工具提供了整合和支援,把強制性的外部依賴降到了最低,這樣就不需要為了簡單地使用Spring而去尋找和下載大量的jar包了。基本的依賴注入只有一個強制性的外部依賴,那就是日誌管理(參考下面關於日誌管理選項的詳細描述)。

下面列出依賴於Spring的應用的基本配置步驟,首先使用Maven,然後Gradle,最後Ivy。在所有案例中,如果有什麼不清楚的地方,參考所用的依賴管理系統的文件或檢視一些範例程式碼——Spring構建時本身使用Gradle管理依賴,所以我們的範例大部分使用Gradle或Maven。

如果使用Maven作為依賴管理工具,甚至不需要明確地提供日誌管理的依賴。例如,建立應用上下文並使用依賴注入配置應用程式,Maven的依賴關係看起來像下面一樣:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.0.RELEASE</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

就這樣,注意如果不需要編譯Spring API,可以把scope宣告為runtime,這是依賴注入使用的典型案例。

上面的示例使用Maven中央倉庫,如果使用Spring的Maven倉庫(例如,里程碑或開發快照),需要在Maven配置中指定倉庫位置。

release版本:

<repositories>
    <repository>
        <id>io.spring.repo.maven.release</id>
        <url>http://repo.spring.io/release/</url>
        <snapshots><enabled>false</enabled></snapshots>
    </repository>
</repositories>

里程碑版本:

<repositories>
    <repository>
        <id>io.spring.repo.maven.milestone</id>
        <url>http://repo.spring.io/milestone/</url>
        <snapshots><enabled>false</enabled></snapshots>
    </repository>
</repositories>

快照版本:

<repositories>
    <repository>
        <id>io.spring.repo.maven.snapshot</id>
        <url>http://repo.spring.io/snapshot/</url>
        <snapshots><enabled>true</enabled></snapshots>
    </repository>
</repositories>

使用Maven時可能會不小心混合了Spring不同版本的jar包。例如,你可能會發現第三方庫或其它的Spring專案存在舊版本的傳遞依賴。如果沒有明確地宣告直接依賴,各種各樣不可預料的情況將會出現。

為了解決這個問題,Maven提出了“物料清單式”(BOM)依賴的概念。可以在dependencyManagement部分匯入spring-framework-bom以保證所有的Spring依賴(不管直接還是傳遞依賴)使用相同的版本。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-framework-bom</artifactId>
            <version>4.3.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

使用BOM的另外一個好處是不再需要指定<version>屬性了:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
    </dependency>
<dependencies>

為了在Gradle構建系統中使用Spring倉庫,需要在repositories部分包含合適的URL:

repositories {
    mavenCentral()
    // and optionally...
    maven { url "http://repo.spring.io/release" }
}

可以酌情把repositories URL中的/release修改為/milestone/snapshot。一旦倉庫配置好了,就可以按Gradle的方式宣告依賴關係了。

dependencies {
    compile("org.springframework:spring-context:4.3.0.RELEASE")
    testCompile("org.springframework:spring-test:4.3.0.RELEASE")
}

使用Ivy管理依賴關係有相似的配置選項。

ivysettings.xml中新增resolver配置使Ivy指向Spring倉庫:

<resolvers>
    <ibiblio name="io.spring.repo.maven.release"
            m2compatible="true"
            root="http://repo.spring.io/release/"/>
</resolvers>

可以酌情把root URL中的/release修改為/milestone/snapshot。一旦配置好了,就可以按照慣例新增依賴了(在ivy.xml中):

<dependency org="org.springframework"
    name="spring-core" rev="4.3.0.RELEASE" conf="compile->runtime"/>

雖然使用支援依賴管理的構建系統是獲取Spring框架的推薦方法,但是也支援通過下載Spring的發行版zip檔案獲取。

發行版zip檔案釋出在了Sprng的Maven倉庫上(這只是為了方便,不需要額外的Maven或其它構建系統去下載它們)。

瀏覽器中開啟http://repo.spring.io/release/org/springframework/spring,並選擇合適版本的子目錄,就可以下載發行版的zip檔案了。發行檔案以-dist.zip結尾,例如,spring-framework-{spring-version}-RELEASE-dist.zip。發行檔案也包含里程碑版本和快照版本。

對於Spring來說日誌管理是非常重要的依賴關係,因為a)它是唯一的強制性外部依賴,b)每個人都喜歡從他們使用的工具看到一些輸出,c)Spring集成了許多其它工具,它們都選擇了日誌管理的依賴。應用程式開發者的目標之一通常是在整個應用程式(包括所有的外部元件)的中心位置統一配置日誌管理,這是非常困難的因為現在有很多日誌管理的框架可供選擇。

Spring中強制的日誌管理依賴是Jakarta Commons Logging API(JCL)。我們編譯了JCL,並使JCL的Log物件對繼承了Spring框架的類可見。對使用者來說所有版本的Spring使用相同的日誌管理庫很重要:遷移很簡單因為Spring儲存了向後相容,即使對於擴充套件了Spring的應用也能向後相容。我們是怎麼做到的呢?我們讓Spring的一個模組明確地依賴於commons-logging(JCL的典型實現),然後讓所有其它模組都在編譯期依賴於這個模組。例如,使用Maven,你想知道哪裡依賴了commons-logging,其實是Spring確切地說是其核心模組spring-core依賴了。

commons-logging的優點是不需要其它任何東西就可以使應用程式運轉起來。它擁有一個執行時發現演算法用於在classpath中尋找其它日誌管理框架並且適當地選擇一個使用(或者告訴它使用哪個)。如果不需要其它的功能了,你就可以從JDK(java.util.logging或JUL)得到一份看起來很漂亮的日誌了。你會發現大多數情況下你的Spring應用程式工作得很好且日誌很好地輸出到了控制檯,這很重要。

不幸的是,commons-logging的執行時發現演算法雖然對於終端使用者很方便,但存在一定的問題。如果我們能讓時光倒流,重新開始Spring專案,我們會使用不同的日誌管理依賴。首要選擇可能是Simple Logging Facade for Java(SLF4J),它也被用於了其它一些使用Spring的工具中。

有兩種方式關掉commons-logging

  1. spring-core模組中去除對commons-logging的依賴(因為這是唯一明確依賴於commons-logging的地方)
  2. 依賴於一個特定的commons-logging且把其jar包換成一個空jar包(具體做法參考SLF4J FAQ

如下,在dependencyManagement中新增部分程式碼就可以排除掉commons-logging了:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.0.RELEASE</version>
        <exclusions>
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

現在這個應用可能是殘缺的,因為在classpath上沒有JCL API的實現,所以需要提供一個新的去修復它。下個章節我們將以SLF4J為例子為JCL提供一個替代實現。

SLF4J是一個更乾淨的依賴,且執行時比commons-logging更有效率,因為它使用編譯期而非執行時繫結其它日誌管理框架。這也意味著你不得不明確地指出執行時想做什麼,並定義和配置它。SLF4J可以繫結許多公共的日誌管理框架,所以通常你可以選擇一個已經使用的,繫結它並配置和管理。

SLF4J可以繫結許多公共的日誌管理框架,包括JCL,同時也是其它日誌管理框架和它本身的橋樑。所以為了在Spring中使用SLF4J,需要用SLF4J-JCL橋樑代替commons-logging依賴。一旦這樣做了然後日誌記錄從Spring內部呼叫轉變成呼叫SLF4J API,因此,如果應用中的其它庫使用了這個API,然後將有一個統一的地方用於配置和管理日誌。

通常的選擇是把Spring橋接到SLF4J,然後從SLF4J到Log4J提供明確的繫結。需要提供4個依賴關係(且排除掉commons-logging):橋樑、SLF4J API、繫結到Log4J和Log4J的實現本身。在Maven中看起來像下面一樣:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.0.RELEASE</version>
        <exclusions>
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.5.8</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.5.8</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.5.8</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.14</version>
    </dependency>
</dependencies>

似乎這麼多依賴僅僅用於獲取日誌。在類載入器問題上,它應該表現得比commons-logging更好,尤其是在像OSGi這樣嚴格的容器中。而且,它也有效能優勢因為繫結發生在編譯期而非執行時。

對於SLF4J使用者更普遍的選擇是直接繫結Logback,這需要更少的步驟,生成更少的依賴。這樣移除了額外的繫結因為Logback直接實現了SLF4J,所以僅僅需要兩個庫即可而不用四個庫(jcl-over-slf4jlogback)。這樣做的話還需要把slf4j-api依賴從其它外部依賴(不是Spring)中排除掉,因為在classpath下僅僅需要一個版本的API。

許多人使用Log4J作為日誌管理框架。它是高效和完善的,實際上在構建和測試Spring的時候我們執行時就是使用它。Spring也提供了一些工具用於配置和初始化Log4J,所以某些模組在編譯期可以選擇依賴於Log4J。

為了使Log4J代替預設的JCL依賴(commons-logging),僅僅提供一個配置檔案(log4j.propertieslog4j.xml)放在classpath根目錄下即可。Maven中的配置如下:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.14</version>
    </dependency>
</dependencies>

下面是log4j.properties的樣例,用於列印日誌到控制檯:

log4j.rootCategory=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n

log4j.category.org.springframework.beans.factory=DEBUG

許多人在一個容器中執行Spring應用程式,而這個容器本身又提供了JCL的實現。IBM的Websphere Application Server(WAS)是一個原型。這經常引起一些問題,而且不幸的是沒有很好的解決方案,簡單地從應用中排除掉commons-logging在大部分情況下還不夠。

更清楚地描述:這個問題通常並不與JCL本身有關,甚至是commons-logging,而是他們綁定了commons-logging到另一個框架(通常是Log4J)。這會失敗是因為commons-logging改變了在舊版本(1.0)和新版本(1.1)中執行執行時發現演算法的方式,其中,舊版本在一些容器中還在使用,新版本是現在大部分人使用的。Spring沒有使用JCL API的其它部分,所以不會有什麼問題,但是一旦Spring或你的應用試圖記錄日誌就會發現Log4J不能工作了。(譯者注:此處的意思是即使發生了上面的衝突,Spring也不會去檢查,直接執行的時候需要列印日誌的時候才會出錯)

在WAS這個案例中,最簡單的方法就是倒置類載入器的繼承(IBM稱作“parent last”,即把父類放後面),以便應用程式而不是容器控制JCL依賴。這種選擇並不總是管用的,在公共領域有很多其它建議的替代方案,且你的里程可能會隨著確切的版本和容器的特性而改變。(譯者注:此處的意思是上面介紹的方法並不是唯一的,需要根據不同的版本和容器作出相應的方案)

Spring最初發行於2004年,從那以後有過幾次重大的修改,Spring 2.0提供了XML名稱空間和AspectJ,Spring 2.5包含了註解驅動的配置,Spring 3.0以Java 5+為框架的程式碼基礎,並使用其新特性,諸如以@Configuration註解的模型等。

4.0版本是最近一次重大的修改,且首次全面支援Java 8的新特性。你仍然可以繼續使用Java的舊版本,但是最低要求提升到了Java SE 6。我們也利用這次重大修改移除了很多過時的類和方法。

新的spring.io網址提供了完整的入門指南幫你學習Spring。更多的指南請參考本文件的 1. Spring入門。新網址也提供了對釋出在Spring下的許多專案的深入理解。

如果你是Maven使用者,你可能會對現在釋出在每個Spring版本中的物料清單POM檔案感興趣。

4.0版本移除了所有過時的包以及許多過時的類和方法。如果從之前的版本升級過來,則需要保證修復所有對過時API的呼叫。

注意,可選的第三方依賴已經升級到2010/2011的版本(也就是說,Spring 4只支援釋出在2010年之後的版本),尤其是,Hibernate 3.6+,EhCache 2.1+,Quartz 1.8+,Groovy 1.8+,Joda-Time 2.0+。有一個例外,Spring 4需要Hibernate Validator 4.3+和Jackson2.0+(Spring 3.2保留了對Jackson1.8/1.9的支援,但現在過時了)。

Spring 4.0對Java 8的幾個新特性提供了支援,允許使用lambda表示式,在Spring回撥介面中使用方法引用。對java.timeJSR-310)有很好地支援,把幾個已存在的註解改造為@Repeatable,還可以使用java 8的引數名稱發現作為替代方案來編譯啟用了除錯資訊的程式碼(基於-parameters的編譯器標誌,譯者注:引數名稱發現是通過反射獲取引數的名稱,而不是型別)。

Spring保留了對舊版本Java和JDK的相容,具體地說是Java SE 6和更高版本都全面支援(最低JDK6.18,釋出於2010年1月)。儘管如此,我們依然建議基於Spring 4的新專案使用Java 7或者8。

Java EE 6+及其相關的JPA 2.0和Servlet 3.0,被認為是Spring 4的基線。為了相容Google App Engine和舊的應用伺服器,可能要在Servlet 2.5環境中部署Spring 4。然而,Servlet 3.0+是我們強烈推薦的,並且它也是Spring測試的先決條件,也是模擬軟體包測試開發環境設定的先決條件。

如果你是WebSphere 7使用者,請一定要安裝JPA 2.0包,如果是WebLogic 10.3.4或更高版本,還要安裝JPA 2.0補丁,這樣Spring 4才能相容這兩個伺服器。

更有遠見的主意,Spring 4.0現在支援Java EE 7適用的規範,尤其是JMS 2.0、JTA 1.2、JPA 2.1、Bean Validation 1.1和JSR-236 Concurrency Utilities。像往常一樣,這種支援只針對個人的使用,比如在Tomcat或獨立的環境中。儘管如此,當Spring應用部署在Java EE 7的伺服器上依然執行良好。

注意,Hibernate 4.3是JPA 2.1的提供者,因此只在Spring 4.0中支援。同樣地,Hibernate Validator 5.0是Bean Validation 1.1的提供者。因此,這兩項並不被Spring 3.2官方支援。

從Spring 4.0開始,可以使用Groovy DSL定義外部bean了。在概念上,這與使用XML配置bean類似,但是可以使用更簡潔的語法。使用Groovy還可以很容易地把bean定義直接嵌入到引導程式碼中。例如:

def reader = new GroovyBeanDefinitionReader(myApplicationContext)
reader.beans {
    dataSource(BasicDataSource) {
        driverClassName = "org.hsqldb.jdbcDriver"
        url = "jdbc:hsqldb:mem:grailsDB"
        username = "sa"
        password = ""
        settings = [mynew:"setting"]
    }
    sessionFactory(SessionFactory) {
        dataSource = dataSource
    }
    myService(MyService) {
        nestedBean = { AnotherBean bean ->
            dataSource = dataSource
        }
    }
}

更多資訊請查閱GroovyBeanDefinitionReaderjavadocs

核心容器有以下幾點改進:

  • Spring注入Bean時把泛型當作一種限定符。例如,使用Spring的Repository時,可以注入特定的實現:
    @Autowired Repository<Customer> customerRepository
  • 使用Spring的元註解,可以開發暴露特定屬性的自定義註解
  • Bean可以在被裝配到list或陣列中時排好序。通過@Order註解和Ordered介面支援。
  • @Lazy註解可以用於注入點,也可用於@Bean定義上。
  • 通過@Conditional註解可以定義有條件過濾的bean。這與@Profile類似但允許使用者自定義開發策略。
  • 基於CGLIB的代理類不再需要預設的構造方法。通過objenesis庫進行支援,它被重新打包到Spring中並作為Spring框架的一部分發布。使用這種策略,生成代理例項時沒有構造方法將被呼叫。
  • 添加了管理時區的支援。例如LocaleContext

保留了Servlet 2.5伺服器的部署,但Spring 4.0現在主要關注Servlet 3.0+環境的部署。如果使用Spring MVC測試框架,需要保證在test classpath上包含Servlet 3.0的相容JAR包。

除了下面要講的WebSocket方面的支援,在Spring的Web模組還包含以下幾點改進:

新的spring-websocket模組全面支援在web應用中客戶端與服務端基於WebSocket雙向通訊。它相容JSR-356、Java WebSocket API,另外還提供了基於SockJS的後退選項(例如,WebSocket模擬)用於不支援WebSocket協議的瀏覽器(例如,IE < 10)。

新的spring-messaging模組支援STOMP作為WebSocket的子協議與一個註解程式模型一起用於路由並處理來自WebSocket客戶端的STOMP訊息。因此,一個@Controller可以同時包含@RequestMapping@MessageMapping方法用於處理HTTP請求和來自WebSocket客戶端的訊息。新的spring-messaging模組還包含從以前Spring整合專案提取出來的關鍵抽象作為基於訊息處理的應用的基礎,如MessageMessageChannelMesaageHandler等。

除了移除了spring-test模組過時的程式碼,Spring 4.0還引入了幾個新特性用於單元測試和整合測試:

  • 幾乎spring-test模組的所有註解(例如,@ContextConfiguration@WebAppConfiguration@ContextHierarchy@ActiveProfiles等)都可以作為元註解用於建立自定義註解並減少測試套件中的重複配置。
  • 有效的bean定義配置檔案可以通過程式設計解析,只要簡單地實現自定義的ActiveProfilesResolver並註冊@ActiveProfilesresolver屬性即可。
  • spring-core模組引入了新的SocketUtils類,用於掃描本地空閒的TCP和UDP服務埠。這項功能並不特定用於測試,但是當寫需要socket的整合測試時非常有用,例如,啟動記憶體中的SMTP伺服器、FTP伺服器、Servlet容器等的測試。
  • 自Spring 4.0起,org.springframework.mock.web包中模擬集合以Servlet 3.0為基礎。此外,一些Servlet API模擬(例如,MockHttpServletRequestMockServletContext等)有少許增強並可通過配置改進。

Spring 4.1引入了一個更簡單的方法來註冊JMS監聽器,那就是使用@JmsListener註解bean的方法。XML的名稱空間也得到了增強以支援這項新特性(jms:annotation-driven),也可以通過Java配置來完全使用這項新特性(@EnableJmsJmsListenerContainerFactory),還可以使用JmsListenerConfigurer來程式設計式地註冊監聽器。

Spring 4.1還可以與4.0中引入的spring-messaging合作使用:

  • 訊息監聽器可以擁有更彈性的簽名,並且可以受益於標準的訊息處理註解,比如,@Payload, @Header, @Headers, @SendTo,等等,也可以使用標準的Message代替javax.jms.Message作為方法的引數。
  • 新的JmsMessageOperation介面可以被使用,並且允許JmsTemplate像使用Message一樣操作。

最後,Spring 4.1還提供了以下各種各樣的改進:

  • JmsTemplate支援同步的請求應答操作。
  • 每個<jms:listener>元素可以指定監聽器的優先順序。
  • 通過BackOff實現可以配置訊息監聽容器的恢復選項。
  • JMS 2.0支援共享消費者。

Spring 4.1支援JCache(JSR-107)註解,直接使用Spring已存在的快取配置和基礎架構即可,不需要其它的改變。

Spring 4.1也極大地改進了它的快取策略:

  • 可以在執行時使用CacheResolver解析快取。因此,不再強制使用value引數來定義快取的名稱。
  • 更多自定義的操作:快取解析,快取管理,鍵生成器。
  • 新的@CacheConfig註解允許通用設定在類級別共享,而不需要啟用任何快取操作。
  • 使用CacheErrorHandler更好地處理快取的異常。

Spring 4.1還為了新增putIfAbsent方法對CacheInterface做了重大改變。

  • 新的抽象ResourceResolver, ResourceTransformerResourceUrlProvider擴充套件了已存在的基於ResourceHttpRequestHandler的資源處理程式。一些內建的實現提供了對帶版本的資源URL(為了有效的HTTP快取)、定位gzip資源、生成HTML 5 AppCache清單等的支援。參考21.16.9 資源服務
  • JDK 1.8的java.util.Optional現在支援@RequestParam, @RequestHeader@MatrixVariable控制器方法的引數。
  • ListenableFuture作為返回值替代了DeferredResult,在這方面一項基礎服務(或者說對AsyncRestTemplate的呼叫)已經返回了ListenableFuture
  • @ModelAttribute方法現在按照依賴間的順序依次被呼叫。
  • Jackson的@JsonView直接作用於@ResponseBodyResponseEntity控制器方法,用於序列化同一個POJO的不同形式(比如,彙總和詳情)。這可以通過為模型屬性