隨筆:有人曾這樣評價spring,說它是Java語言的一個巔峰之作,稱呼它為Java之美,今天,小編就領大家一起來領略一下spring之美!
Spring官方文檔:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/
聲明:此文章大部分轉載自唐彤,本人只是在原基礎上略作修改,對原文有興趣的可以戳連接:
在談spring之前,完美可以先看一下從官網結果來的圖(當然是翻譯后的啦~),讓大家有一個大概的了解:
一、Spring框架概述
Spring框架是一個輕量級的解決方案,可以一站式地構建企業級應用。Spring是模塊化的,所以可以只使用其中需要的部分。可以在任何web框架上使用控制反轉(IoC),也可以只使用Hibernate集成代碼或JDBC抽象層。它支持聲明式事務管理、通過RMI或web服務實現遠程訪問,並可以使用多種方式持久化數據。它提供了功能全面的MVC框架,可以透明地集成AOP到軟件中。
Spring被設計為非侵入式的,這意味着你的域邏輯代碼通常不會依賴於框架本身。在集成層(比如數據訪問層),會存在一些依賴同時依賴於數據訪問技術和Spring,但是這些依賴可以很容易地從代碼庫中分離出來。
本文檔是Spring框架的參考指南,如果你有任何請求、評論或問題,請給我們發郵件,關於框架本身的問題將在StackOverflow上討論(見https://spring.io.questions)。
1. Spring入門
這篇參考指南提供了Spring框架的詳細信息,包括了對所有功能的全面理解,同時也包括一些重要概念的背景(比如,依賴注入)。
如果你才開始使用Spring,可以通過創建一個基於Spring Boot的應用開始使用Spring框架。Spring Boot提供了一種快速創建Spring應用的方式,它基於Spring框架,支持約定優於配置,使你可以盡快啟動並運行。
可以使用start.spring.io或遵循入門指南(比如,構建RESTful web應用入門)生成一個基本的項目。除了易於理解,這些指南聚集於一個個任務,它們大部分都是基於Spring Boot的,同時也包含了Spring包下的其它項目,以便你可以考慮何時使用它們解決特定的問題。
2. 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應用程序進行消息交換,並且通過提供標准的產生、發送、接收消息的接口簡化企業應用的開發。
2.1 依賴注入(DI)和控制反轉(IoC)
一個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框架概述
下面列出了每項功能對應的模塊及其主題,它們都有人性的名字(artifact name),這些名字與依賴管理工具中的artifact id 是相互對應的。
2.2.1 核心容器(Core Container)
核心容器包括spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring表達式語言,Spring Expression Language)等模塊。
spring-core和spring-beans模塊是Spring框架的基礎,包括控制反轉和依賴注入等功能。BeanFactory是工廠模式的微妙實現,它移除了編碼式單例的需要,並且可以把配置和依賴從實際編碼邏輯中解耦。
Context(spring-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容器檢索對象,還支持列表的投影、選擇以及聚合等。
2.2.2 AOP和檢測(Instrumentation)
spring-aop模塊提供了面向切面編程(AOP)的實現,可以定義諸如方法攔截器和切入點等,從而使實現功能的代碼徹底的解耦出來。使用源碼級的元數據,可以用類似於.Net屬性的方式合並行為信息到代碼中。
spring-aspects模塊提供了對AspectJ的集成。
spring-instrument模塊提供了對檢測類的支持和用於特定的應用服務器的類加載器的實現。spring-instrument-tomcat模塊包含了用於tomcat的Spring檢測代理。
2.2.3 消息處理(messaging)
Spring 4 包含的spring-messaging模塊是從Spring集成項目的關鍵抽象中提取出來的,這些項目包括Message、MessageChannel、MessageHandler和其它服務於消息處理的項目。這個模塊也包含一系列的注解用於映射消息到方法,這類似於Spring MVC基於編碼模型的注解。
2.2.4 數據訪問與集成
數據訪問與集成層包含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的集成,包括JPA、JDO和Hibernate等。通過此模塊可以讓這些ORM框架和spring的其它功能整合,比如前面提及的事務管理。
spring-oxm模塊提供了對OXM實現的支持,比如JAXB、Castor、XML Beans、JiBX、XStream等。
spring-jms模塊包含生產(produce)和消費(consume)消息的功能。從Spring 4.1開始,集成了spring-messaging模塊。
2.2.5 Web
Web層包括spring-web、spring-webmvc、spring-websocket、spring-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模塊的功能。
2.2.6 Test
spring-test模塊通過JUnit和TestNG組件支持單元測試和集成測試。它提供了一致性地加載和緩存Spring上下文,也提供了用於單獨測試代碼的模擬對象(mock object)。
2.3 使用場景
前面提及的構建模塊使得Spring在很多場景成為一種合理的選擇,不管是資源受限的嵌入式應用還是使用了事務管理和web集成框架的成熟的企業級應用。
圖2.2. 典型的成熟的Spring web應用程序
Spring的聲明式事務管理可以使web應用完成事務化,就像使用EJB容器管理的事務。所有客制的業務邏輯都可以使用簡單的POJO實現,並用Spring的IoC容器進行管理。另外,還包括發郵件和驗證功能,其中驗證功能是從web層分離的,由你決定何處執行驗證。Spring的ORM可以集成JPA、Hibernate和JDO等,比如,使用Hibernate時,可以繼續使用已存在的映射文件和標准的Hibernate的SessionFactory配置。表單控制器無縫地把web層和領域模型集成在一起,移除了ActionForms和其它把HTTP參數轉換成領域模型的類。
圖2.3. 使用第三方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
Spring框架也為EJB提供了訪問抽象層,可以重新使用現有的POJO並把它們包裝到無狀態的會話bean中,以使其用於可擴展的安全的web應用中。
2.3.1 依賴管理和命名約定
依賴管理和依賴注入是兩碼事。為了讓應用程序擁有這些Spring的非常棒的功能(如依賴注入),需要導入所需的全部jar包,並在運行時放在classpath下,有可能的話編譯期也應該放在classpath下。這些依賴並不是被注入的虛擬組件,而是文件系統上典型的物理資源。依賴管理的處理過程涉及到定位這些資源、存儲並添加它們到classpath下。依賴可能是直接的(比如運行時依賴於Spring),也可能是間接的(比如依賴於commons-dbcp,commons-dbcp又依賴於commons-pool)。間接的依賴又被稱作“傳遞”,它們是最難識別和管理的。
如果准備使用Spring,則需要拷貝一份所需模塊的Spring的jar包。為了便於使用,Spring被打包成一系列的模塊以盡可能地減少依賴,比如,如果不是在寫一個web應用,那就沒必要引入spring-web模塊。這篇文檔中涉及到的Spring模塊,我們使用spring-*或spring-*.jar的命名約定,其中,*代表模塊的短名字(比如,spring-core、spring-webmvc、spring-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對大部分企業和其它外部工具提供了集成和支持,把強制性的外部依賴降到了最低,這樣就不需要為了簡單地使用Spring而去尋找和下載大量的jar包了。基本的依賴注入只有一個強制性的外部依賴,那就是日志管理(參考下面關於日志管理選項的詳細描述)。
下面列出依賴於Spring的應用的基本配置步驟,首先使用Maven,然后Gradle,最后Ivy。在所有案例中,如果有什么不清楚的地方,參考所用的依賴管理系統的文檔或查看一些范例代碼——Spring構建時本身使用Gradle管理依賴,所以我們的范例大部分使用Gradle或Maven。
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的“物料清單式”依賴
使用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依賴關系管理
為了在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依賴關系管理
使用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"/>
發行版的Zip文件
雖然使用支持依賴管理的構建系統是獲取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。發行文件也包含里程碑版本和快照版本。
2.3.2 日志管理
對於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
不幸的是,commons-logging的運行時發現算法雖然對於終端用戶很方便,但存在一定的問題。如果我們能讓時光倒流,重新開始Spring項目,我們會使用不同的日志管理依賴。首要選擇可能是Simple Logging Facade for Java(SLF4J),它也被用於了其它一些使用Spring的工具中。
有兩種方式關掉commons-logging:
- 從spring-core模塊中去除對commons-logging的依賴(因為這是唯一明確依賴於commons-logging的地方)
- 依賴於一個特定的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
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-slf4j和logback)。這樣做的話還需要把slf4j-api依賴從其它外部依賴(不是Spring)中排除掉,因為在classpath下僅僅需要一個版本的API。
使用Log4J
許多人使用Log4J作為日志管理框架。它是高效和完善的,實際上在構建和測試Spring的時候我們運行時就是使用它。Spring也提供了一些工具用於配置和初始化Log4J,所以某些模塊在編譯期可以選擇依賴於Log4J。
為了使Log4J代替默認的JCL依賴(commons-logging),僅僅提供一個配置文件(log4j.properties或log4j.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
帶有本地JCL的運行時容器
許多人在一個容器中運行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 4.x中的新特性
3. Spring 4.0的新特性和增強功能
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 4.0的指導手冊參見Spring Framework GigHub Wiki。
3.1 改進了入門體驗
新的spring.io網址提供了完整的入門指南幫你學習Spring。更多的指南請參考本文檔的 1. Spring入門。新網址也提供了對發布在Spring下的許多項目的深入理解。
如果你是Maven用戶,你可能會對現在發布在每個Spring版本中的物料清單POM文件感興趣。
3.2 移除了過時的包和方法
4.0版本移除了所有過時的包以及許多過時的類和方法。如果從之前的版本升級過來,則需要保證修復所有對過時API的調用。
完整的改變請參考API Differences Report。
注意,可選的第三方依賴已經升級到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的支持,但現在過時了)。
3.3 Java 8(以及6和7)
Spring 4.0對Java 8的幾個新特性提供了支持,允許使用lambda表達式,在Spring回調接口中使用方法引用。對java.time(JSR-310)有很好地支持,把幾個已存在的注解改造為@Repeatable,還可以使用java 8的參數名稱發現作為替代方案來編譯啟用了調試信息的代碼(基於-parameters的編譯器標志,譯者注:參數名稱發現是通過反射獲取參數的名稱,而不是類型)。
Spring保留了對舊版本Java和JDK的兼容,具體地說是Java SE 6和更高版本都全面支持(最低JDK6.18,發布於2010年1月)。盡管如此,我們依然建議基於Spring 4的新項目使用Java 7或者8。
3.4 Java EE 6和7
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官方支持。
3.5 Groovy Bean定義DSL
從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 } } }
更多信息請查閱GroovyBeanDefinitionReader的javadocs。
3.6 核心容器的改進
核心容器有以下幾點改進:
- Spring注入Bean時把泛型當作一種限定符。例如,使用Spring的Repository時,可以注入特定的實現:
@Autowired Repository<Customer> customerRepository。 - 使用Spring的元注解,可以開發暴露特定屬性的自定義注解。
- Bean可以在被裝配到list或數組中時排好序。通過@Order注解和Ordered接口支持。
- @Lazy注解可以用於注入點,也可用於@Bean定義上。
- 引入了@Description注解以便開發者使用基於Java的配置。
- 通過@Conditional注解可以定義有條件過濾的bean。這與@Profile類似但允許用戶自定義開發策略。
- 基於CGLIB的代理類不再需要默認的構造方法。通過objenesis庫進行支持,它被重新打包到Spring中並作為Spring框架的一部分發布。使用這種策略,生成代理實例時沒有構造方法將被調用。
- 添加了管理時區的支持。例如LocaleContext。
3.7 Web的改進
保留了Servlet 2.5服務器的部署,但Spring 4.0現在主要關注Servlet 3.0+環境的部署。如果使用Spring MVC測試框架,需要保證在test classpath上包含Servlet 3.0的兼容JAR包。
除了下面要講的WebSocket方面的支持,在Spring的Web模塊還包含以下幾點改進:
- 可以添加新的@RestController注解到Spring MVC應用上,而不用再添加@ResponseBody到每個@RequestMapping方法上。
- 添加了AsyncRestTemplate類,當開發REST客戶端時允許非阻塞異步支持。
- 當開發Spring MVC應用時提供了全面的時區支持。
3.8 WebSocket、SockJS 和STOMP Messaging
新的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集成項目提取出來的關鍵抽象作為基於消息處理的應用的基礎,如Message、MessageChannel、MesaageHandler等。
更詳細的內容請參考 25 WebSocket支持 章節。
3.9 測試的改進
除了移除了spring-test模塊過時的代碼,Spring 4.0還引入了幾個新特性用於單元測試和集成測試:
- 幾乎spring-test模塊的所有注解(例如,@ContextConfiguration、@WebAppConfiguration、@ContextHierarchy、@ActiveProfiles等)都可以作為元注解用於創建自定義注解並減少測試套件中的重復配置。
- 有效的bean定義配置文件可以通過編程解析,只要簡單地實現自定義的ActiveProfilesResolver並注冊@ActiveProfiles的resolver屬性即可。
- spring-core模塊引入了新的SocketUtils類,用於掃描本地空閑的TCP和UDP服務端口。這項功能並不特定用於測試,但是當寫需要socket的集成測試時非常有用,例如,啟動內存中的SMTP服務器、FTP服務器、Servlet容器等的測試。
- 自Spring 4.0起,org.springframework.mock.web包中模擬集合以Servlet 3.0為基礎。此外,一些Servlet API模擬(例如,MockHttpServletRequest,MockServletContext等)有少許增強並可通過配置改進。
4. Spring 4.1的新特性和增強功能
4.1 JMS的改進
Spring 4.1引入了一個更簡單的方法來注冊JMS監聽器,那就是使用@JmsListener注解bean的方法。XML的命名空間也得到了增強以支持這項新特性(jms:annotation-driven),也可以通過Java配置來完全使用這項新特性(@EnableJms,JmsListenerContainerFactory),還可以使用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支持共享消費者。
4.2 緩存的改進
Spring 4.1支持JCache(JSR-107)注解,直接使用Spring已存在的緩存配置和基礎架構即可,不需要其它的改變。
Spring 4.1也極大地改進了它的緩存策略:
- 可以在運行時使用CacheResolver解析緩存。因此,不再強制使用value參數來定義緩存的名稱。
- 更多自定義的操作:緩存解析,緩存管理,鍵生成器。
- 新的@CacheConfig注解允許通用設置在類級別共享,而不需要啟用任何緩存操作。
- 使用CacheErrorHandler更好地處理緩存的異常。
Spring 4.1還為了添加putIfAbsent方法對CacheInterface做了重大改變。
4.3 Web的改進
- 新的抽象ResourceResolver, ResourceTransformer和ResourceUrlProvider擴展了已存在的基於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直接作用於@ResponseBody和ResponseEntity控制器方法,用於序列化同一個POJO的不同形式(比如,匯總和詳情)。這可以通過為模型屬性添加指定key的序列化視圖類型來渲染視圖。參考Jackson序列化視圖支持。
- Jackson現在支持JSONP。參考Jackson JSONP支持。
- 新的生命周期選項可用於在控制器方法返回后且響應寫出前攔截@ResponseBody和ResponseEntity方法,聲明一個@ControllerAdvice bean實現ResponseBodyAdvice即可,內置的@JsonView和JSONP恰恰利用了這點。參考21.4.1 使用HandlerInterceptor攔截請求。
- 有三個HttpMessageConverter選項:
- Gson——比Jackson更輕的足跡,已用於Spring Android中。
- Google協議緩沖——企業內部有效的服務間通信數據協議,但是也可以作為JSON和XML暴露於瀏覽器中。
- 通過jackson-dataformat-xml擴展支持基於XML的Jackson。當使用@EnableWebMvc或<mvc:annotation-driven>時,如果classpath下存在jackson-dataformat-xml則默認會替代JAXB2。
- 類似JSP的視圖現在可以通過引用控制器映射的名稱與控制器建立鏈接。默認的名稱將被賦給每一個@RequestMapping。例如,FooController擁有方法handleFoo,它的名稱為“FC#handleFoo”。命名策略是可插拔的,也可以通過name屬性為@RequestMapping明確地命名。在Spring JSP標簽庫中新的mvcUrl功能可以讓使用JSP頁面變得更方便。參考21.7.2 從視圖為Controller及其方法創建URI。
- ResponseEntity提供了創建者風格的API用於引導控制器方法為服務端響應做准備。例如,ResponseEntity.ok()。
- RequestEntity是一種新類型,它提供了創建者風格的API用於引導客戶端REST代碼為HTTP請求做准備。
- MVC Java配置與XML命名空間:
- 視圖解析器可以被配置,包含對內容協商的支持。參考21.16.8 視圖解析器。
- 視圖控制器內置了對重定向及設置響應狀態的支持。應用程序可以使用它配置重定向的URL,用視圖渲染 404 響應,發送“無內容”響應,等等。一些用例請點擊這里。
- 內置了自定義的路徑匹配。參考21.16.11 路徑匹配。
- 支持Groovy標記模板(基於Groovy 2.3)。參考GroovyMarkupConfigurer和各自的ViewResolver及視圖實現 。
4.4 WebSocket 消息處理的改進
- 支持SockJS(Java)客戶端。參考SockJsClient和同包下的類。
- 當STOMP客戶端訂閱和取消訂閱時新的應用上下文事件SessionSubscribeEvent和SessionUnsubscribeEvent會被觸發。
- 新的作用域“websocket”。參考25.4.14 WebSocket作用域。
- @SendToUser只能把單會話作為目標,而且不需要用戶身份驗證。
- @MessageMapping方法可以使用點“.”代替斜杠“/”作為分割符。參考SPR-11660。
- STOMP/WebSocket監測信息收集和日志管理。參考25.4.16 運行時監測。
- 得到極大優化和改進的日志管理保留了可讀性和簡潔性,甚至是在DEBUG水平。
- 優化了消息的創建,包含了對臨時消息可變性的支持,並避免自動消息id和時間戳的創建。參考Javadoc中的MessageHeaderAccessor。
- 在WebSocket會話創建60秒后沒有活動則將會關閉STOMP/WebSocket連接。參考SPR-11884。
4.5 測試的改進
- Groovy腳本現在可用於配置ApplicationContext,其中ApplicationContext在測試上下文框架中被加載用於集成測試。參考帶有Groovy腳本的上下文配置。
- 在事務測試方法中可以通過TestTransaction API編程式地開始和結束測試事務。參考編程式事務管理。
- SQL腳本執行可以通過在每個類或方法上添加新的@Sql和@SqlConfig注解聲明式地配置。參考14.5.7執行SQL腳本。
- 可以通過新的@TestPropertySource注解配置用於測試的property源文件,它能夠自動地重寫系統和應用的property源文件。參考帶有測試property源文件的上下文配置。
- 默認的TestExecutionListeners能夠被自動地發現。參考自動發現默認的TestExecutionListeners。
- 自定義的TestExecutionListeners能夠被自動地合並到默認的監聽器中。參考合並TestExecutionListeners。
- 測試上下文框架中事務測試的文檔提供了更多深入的解釋和附加的案例。參考14.5.6 事務管理。
- 對MockServletContext, MockHttpServletRequest和其它Servlet API模擬的各種各樣的改進。
- AssertThrows被重構了用於支持Throwable而不是Exception。
- 在Spring MVC測試中,JSON Assert作為使用JSONPath的額外選項,可以為JSON響應斷言,這就像使用XMLUnit為XML斷言一樣。
- 可以通過MockMvcConfigurer創建MockMvcBuilder。這使得應用Spring安全設置變得很容易,也可用於把通用設置壓縮進任何第三方框架或項目中。
- MockRestServiceServer現在支持AsyncRestTemplate用於客戶端測試。
5. Spring 4.2的新特性和增強功能
5.1 核心容器的改進
- 類似@Bean的注解被發現並用於處理Java 8的默認方法,允許實現接口的配置類帶有默認的@Bean方法。(譯者注:@Bean注解可以用到Java 8接口的默認方法上,然后配置類實現這個接口一樣可以得到bean)
- 配置類現在可以聲明@Import引入普通的組件類了,允許混合引入配置類和組件類。(譯者注:@Import以前只能引入配置類,現在也可以引入沒有任何注解的組件類)
- 配置類可以聲明一個@Order值,按照一定的順序處理(比如,按名稱重寫bean),甚至是在classpath掃描的時候。(譯者注:@Order值大的會覆蓋小的)
- @Resource注入的元素支持@Lazy聲明,像@Autowired一樣,對請求目標的bean接受延遲初始化的代理。
- 應用程序事件現在提供基於注解的模型了,也可以發布任何事件。
- bean中的任何公共方法都能夠通過@EventListener注解來消費事件。
- @TransactionalEventListener提供了事務綁定的事件支持。
-
Spring 4.2提供了一流的支持用於聲明和查找注解屬性的別名。新的@AliasFor注解可以用來在單個注解內聲明一對別名屬性,或者聲明一個從自定義注解屬性到元注解屬性的別名。
- 以下注解都通過@AliasFor翻新過了,以便為value屬性提供更有意義的別名:@Cacheable, @CacheEvict,@CachePut, @ComponentScan, @ComponentScan.Filter, @ImportResource, @Scope,@ManagedResource, @Header, @Payload, @SendToUser, @ActiveProfiles,@ContextConfiguration, @Sql, @TestExecutionListeners, @TestPropertySource, @Transactional,@ControllerAdvice, @CookieValue, @CrossOrigin, @MatrixVariable, @RequestHeader,@RequestMapping, @RequestParam, @RequestPart, @ResponseStatus, @SessionAttributes,@ActionMapping, @RenderMapping, @EventListener, @TransactionalEventListener。
-
例如,來自spring-test模塊的@ContextConfiguration現在定義如下:
public @interface ContextConfiguration { @AliasFor("locations") String[] value() default {}; @AliasFor("value") String[] locations() default {}; // ... }
-
類似地,重寫了元注解屬性的注解現在也可以使用@AliasFor細粒度地控制那些在注解層次結構中被重寫的屬性。實際上,現在可以為元注解的value屬性聲明一個別名。
-
例如,現在可以像下面一樣開發一種重寫了自定義屬性的組合注解。
@ContextConfiguration public @interface MyTestConfig { @AliasFor(annotation = ContextConfiguration.class, attribute = "value") String[] xmlFiles(); // ... }
-
參考Spring注解編程模型。
- Spring在發現元注解的搜索算法上做了很多改進。例如,在注解繼承體系中可以聲明局部的組合注解。
- 重寫了元注解屬性的組合注解現在可以用在接口、抽象類、橋接和接口方法上,也可以用在類、標准方法、構造方法和字段上。
- 代表注解屬性的Map(和AnnotationsAttributes實例)可以被合成(或者轉換)到一個注解中。
- 基於字段的數據綁定(DirectFieldAccessor)可以與當前基於屬性的數據綁定(BeanWrapper)一起使用。特別地,基於字段的綁定現在支持為集合、數據和Map導航。
- DefaultConversionService為Steam、Charset、Currency和TimeZone提供了可以直接使用的轉換器。這些轉換器也可以被添加到任意的ConversionService中。
- DefaultFormattingConversionService為JSR-354中的貨幣提供了支持(如果javax.money存在於classpath下),即MonetaryAmount和CurrencyUnit。這也包含對@NumberFormat的支持。
- @NumberFormat現在可以作為元注解使用。
- JavaMailSenderImpl有一個新的方法testConnection()用於檢查與服務器間的連接。
- ScheduledTaskRegistrar暴露計划的任務。
- Apache的commons-pool2現在支持AOP池CommonsPool2TargetSource。
- 為腳本化bean引入了StandardScriptFactory作為一個基於JSR-223的機制,暴露於XML中的lang:std元素。對JavaScript和JRuby的支持。(注意:JRubyScriptFactory和lang:jruby現在過時了,請使用JSR-223)
5.2 數據訪問的改進
- AspectJ現在支持javax.transactional.Transactional。
- SimpleJdbcCallOperations現在支持命名綁定。
- 全面支持Hibernate ORM 5.0,作為JPA提供者(自動適配),也支持其原生API(被新的org.springframework.orm.hibernate5包覆蓋)。
- 嵌入的數據庫現在可以被自動賦值不同的(unique)名字,且<jdbc:embedded-database>支持新的屬性database-name。參考下面的“測試的改進”部分。
5.3 JMS的改進
- autoStartup屬性可以通過JmsListenerContainerFactory控制。
- 每個監聽器容器都能配置應答Destination的類型。
- @SendTo注解的值現在可以使用SpEL表達式。
- 響應目標可以使用JmsResponse在運行時計算。
- @JmsListener是一個可重復性的注解,可以在同一個方法上聲明多個JMS容器(如果你還沒有使用Java 8,請使用新引入的@JmsListeners)。
5.4 Web的改進
- 支持HTTP流和服務器發送事件。參考HTTP流。
- 支持內置CORS的全局(MVC Java配置和XML命名空間)和局部(例如,@CrossOrign)配置。參考26 CORS支持。
- HTTP緩存更新:
- 新的創建者CacheControl,嵌入到ResponseEntity, WebContentGenerator,ResourceHttpRequestHandler中。
- 在WebRequest中改進了ETag/Last-Modified的支持。
- 自定義映射注解,使用@RequestMapping作為元注解。
- AbstractHandlerMethodMapping中的公共方法用於在運行時注冊和取消注冊請求映射。
- AbstractDispatcherServletInitializer中的保護方法createDispatcherServlet進一步自定義DispatcherServlet的實例。
- HandlerMethod作為@ExceptionHandler方法的參數,特別在@ControllerAdvice組件中非常便利。
- java.util.concurrent.CompletableFuture作為@Controller方法的返回類型。
- HttpHeaders支持字節范圍的請求,並提供靜態資源。
- @ResponseStatus檢測嵌套異常。
- RestTemplate中的UriTemplateHandler擴展點。
- DefaultUriTemplateHandler暴露了baseUrl屬性和路徑段編碼選項。
- 此擴展點可嵌入到URI模板庫中。
- OkHTTP與RestTemplate集成。
- 自定義的baseUrl可以替代MvcUriComponentsBuilder中的方法。
- 序列化/反序列化的異常信息在WARN級別被記錄。
- 默認的JSON前綴從“{}&&”改成了更安全的”)]}’,”中的一個(譯者注:此處可能官方文檔有誤)。
- 新的擴展點RequestBodyAdvice和內置實現支持@RequestBody方法參數上的Jackson的@JsonView。
- 使用GSON或Jackson 2.6+時,處理器方法的返回類型被用於改進參數化類型的序列化,比如List<Foo>。
- 引入了ScriptTemplateView作為JSR-223用於處理腳本web視圖的機制,主要關注於Nashorn(JDK 8)上的JavaScript視圖模板。
5.5 WebSocket消息處理的改進
- 暴露關於已連接用戶和訂閱存在的信息。
- 新的SimpUserRegistry暴露為叫作“userRegistry”的bean。
- 在服務器集群間共享已存在的信息(參考代理中繼配置選項)。
- 解決用戶在服務器集群中的目的地(參考代理中繼配置選項)。
- StompSubProtocolErrorHandler擴展點用來定制和控制STOMP錯誤幀到客戶端。
- 通過@ControllerAdvice組件聲明的全局方法@MessageExceptionHandler。
- SpEL表達式“selector”頭用於SimpleBrokerMessageHandler的訂閱。
- 通過TCP和WebSocket使用STOMP客戶端。參考25.4.13 STOMP客戶端。
- @SendTo和@SendToUser可以包含多個占位符。
- Jackson的@JsonView支持在@MessageMapping和@SubscribeMapping方法上返回值。
- ListenableFuture和CompletableFuture可以作為@MessageMapping和@SubscribeMapping方法的返回值類型。
- MarshallingMessageConverter用於XML負載。
5.6 測試的改進
- 基於JUnit的集成測試現在可以使用JUnit規則執行而不是SpringJUnit4ClassRunner。這使得基於Spring的集成測試可以使用替代runner運行,比如JUnit的Parameterized或第三方的runner如MockitoJUnitRunner。參考Spring JUnit規則。
- Spring MVC測試框架現在對HtmlUnit提供了一流的支持,包括集成Selenium的WebDriver,允許基於頁面的web應用測試不再需要部署到一個Servlet容器上。參考14.6.2, HtmlUnit的集成。
- AopTestUtils是一個新的測試工具類,它允許開發者可以獲取到底層的隱藏在一個或多個Spring代理類下的目標對象。參考13.2.1 通用測試工具類。
- ReflectionTestUtils現在支持為static字段設值和取值,包括常量。
- 通過@ActiveProfiles聲明的bean定義配置文件的原始順序現在保留了,這是為了使用一些案例,比如Spring Boot的ConfigFileApplicationListener,它通過有效的名稱來加載配置文件。
- @DirtiesContext現在支持新的模式BEFORE_METHOD, BEFORE_CLASS和BEFORE_EACH_TEST_METHOD用於在測試之前關閉ApplicationContext——例如,在大型測試套件中的一些劣質的測試毀壞了對ApplicationContext的原始配置。
- @Commit這個新注解可以直接替代@Rollback(false)。
- @Rollback現在可以用來配置類級別默認的回滾語義。
- 因此,@TransactionConfiguration現在過時了,並且會在后續版本中移除。
- 通過statements這個新的屬性@Sql現在支持內聯SQL語句的執行。
- 用於在測試期間緩存應用上下文的ContextCache現在是公共的API,它有默認的實現,可以替代自定義的緩存需求。
- DefaultTestContext, DefaultBootstrapContext和DefaultCacheAwareContextLoaderDelegate現在是support子包下的公共類,允許自定義擴展。
- TestContextBootstrappers現在負責創建TestContext。
- 在Spring MVC測試框架中,MvcResult的詳細日志現在可以在DEBUG級別被打印,或者寫出到自定義的OutputStream或Writer中。參考MockMvcResultHanlder中的新方法log(), print(OutputStream)和print(Writer)。
- JDBC XML的命名空間支持一個新的屬性database-name,位於<jdbc:embedded-database>中,允許開發者為嵌入的數據庫設置不同的名字——例如,通過SpEl表達式或者被當前 有效bean定義 配置文件 影響的屬性文件占位符。
- 嵌入的數據庫現在可以被自動賦予不同的名字,允許在同一測試套件不同的應用上下文中重復使用通用的測試數據庫配置。參考18.8.6 為嵌入的數據庫生成不同的名字。
- MockHttpServletRequest和MockHttpServletResponse現在通過getDateHeader和setDateHeader方法提供了更好的支持用於格式化日期頭。
6. Spring 4.3的新特性和增強功能
6.1 核心容器的改進
- 核心容器提供了更豐富的元數據用於編程式評估。
- Java8的默認方法可以作為bean屬性的getter/setter方法被檢測。
- 如果目標bean僅僅定義了一個構造方法,就不必指定@Autowired注解了。
- @Configuration類支持構造方法注入。
- 任何用於指定@EventLIstener條件的SpEL表達式現在可以引用bean了(例如,@beanName.method())。
- 組合注解現在可以重寫元注解的數組屬性。例如,@RequestMapping的String[] path可以使用組合注解的String path重寫。
- @Scheduled和@Schedules可以作為元注解,用來創造組合注解並可重寫其屬性。
- @Scheduled支持任何作用域的bean。
6.2 數據訪問的改進
- jdbc:initialize-database和jdbc:embedded-database支持一個可配置的分隔符應用於任何腳本。
6.3 緩存的改進
spring 4.3 允許並發調用給定的key,從而使得值只被計算一次。這是一項可選功能,通過@Cacheable的新屬性sync啟用。這項功能也使Cache接口做了重大改變,增加了get(Object key, Callable<T> valueLoader)方法。
spring 4.3 也改進了以下緩存方面的內容:
- 緩存相關的注解中的SpEL表達式現在可以引用bean了(比如,@beanName.method())。
- ConcurrentMapCacheManager和ConcurrentMapCache現在可以通過新的屬性storeByValue序列化緩存的entry。
- @Cacheable, @CacheEvict, @CachePut和@Caching現在可以作為元注解,用來創造組合注解並可重寫其屬性。
6.4 JMS的改進
- @SendTo現在可應用於類級別上,以便共享共同的目標。
- @JmsListener和@JmsListeners現在可作為元注解,用來創造組合注解並可重寫其屬性。
6.5 Web的改進
- 內置了對Http頭和Http選項的支持。
- 新的組合注解@GetMapping, @PostMapping, @PutMapping, @DeleteMapping和@PatchMapping,它們來源於@RequestMapping。
- 新的組合注解@RequestScope, @SessionScope和@ApplicationScope用於web作用域。
- 新的注解@RestControllerAdvice,它是@ControllerAdvice和@ResponseBody的組合體。
- @ResponseStatus現在可用於類級別並可以被所有方法繼承。
- 新的@SessionAttribute注解用於訪問session的屬性。
- 新的@RequestAttribute注解用於訪問request的屬性。
- @ModelAttribute可以設置其屬性binding=false阻止數據綁定。
- 錯誤和自定義的異常可一致地暴露給MVC的異常處理器。
- Http消息轉換器中一致地處理字符集,默認地使用UTF-8處理多部分文本內容。
- 使用已配置的ContentNegotiationManager處理媒體類型等靜態資源。
- RestTemplate和AsyncRestTemplate可通過DefaultUriTemplateHandler支持嚴格的URI編碼。
- AsyncRestTemplate支持請求攔截。
6.6 WebSocket消息處理的改進
- @SendTo和@SendToUser現在可應用於類級別上,以便共享共同的目標。
6.7 測試的改進
- spring測試上下文中的JUnit現在需要 4.12 及其更高版本。
- SpringJUnit4ClassRunner的新別名SpringRunner。
- 測試相關的注解現在可用於接口上,從而可以使用Java 8 中接口的默認方法。
- 空聲明的@ContextConfiguration現在可以完全省略了,如果默認的XML文件、Groovy腳本或@Configuration類被檢測到。
- @Transactional測試方法不再必需是public了(例如,在TestNG和JUnit 5 中)。
- @BeforeTransaction和AfterTransaction方法不再必需是public了,並且現在也可能用在Java 8 接口的默認方法上。
- spring測試上下文中的ApplicationContext緩存現在是有界的,默認最大值為32,並按最近最少原則回收。其最大值可以通過JVM的系統屬性或spring的屬性spring.test.context.cache.maxSize進行設置。
- 用於自定義測試ApplicationContext的新API ContextCustomizer在bean定義之后且上下文刷新之前被加載到上下文中。Customizer可以通過第三方注冊,但需要實現自定義的ContextLoader。
- @Sql和@SqlGroup現在可作為元注解,用來創造組合注解並可重寫其屬性。
- ReflectionTestUtils現在會自動解除代理當set或get一個字段時。
- 服務器端的springmvc測試支持響應頭帶有多個值。
- 服務器端的springmvc測試解析表單數據請求內容並填充請求參數。
- 服務器端的springmvc測試支持對已調用的處理器方法模擬斷言。
- 客戶端的REST測試允許指明希望發送多少次請求並決定是否請求的順序可被忽略。
- 客戶端的REST測試支持在請求體中添加表單數據。
6.8 支持新庫和服務器
- Hibernate ORM 5.2(仍然能很好地支持4.2/4.3和5.0/5.1,但是3.6已經過時了)
- Jackson 2.8(至少需要2.6以上版本)
- OkHttp 3.x(同時仍然支持OkHttp 2.x)
- Netty 4.1
- Undertow 1.4
- Tomcat 8.5.2 及 9.0 M6
另外,spring 4.3的spring-core.jar中集成了更新的ASM 5.1和Objenesis 2.4。