Spring官方文档:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/
#一、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获得哪些好处呢?
译者注:①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),如下图:
下面列出了每项功能对应的模块及其主题,它们都有人性的名字(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集成框架的成熟的企业级应用。
Spring的声明式事务管理可以使web应用完成事务化,就像使用EJB容器管理的事务。所有客制的业务逻辑都可以使用简单的POJO实现,并用Spring的IoC容器进行管理。另外,还包括发邮件和验证功能,其中验证功能是从web层分离的,由你决定何处执行验证。Spring的ORM可以集成JPA、Hibernate和JDO等,比如,使用Hibernate时,可以继续使用已存在的映射文件和标准的Hibernate的SessionFactory配置。表单控制器无缝地把web层和领域模型集成在一起,移除了ActionForms和其它把HTTP参数转换成领域模型的类。
一些场景可能不允许你完全切换到另一个框架。然而,Spring框架不强制你使用它所有的东西,它不是非此即彼(all-or-nothing)的解决方案。前端使用Struts、Tapestry、JSF或别的UI框架可以和Spring中间件集成,从而使用Spring的事务管理功能。仅仅只需要使用ApplicationContext连接业务逻辑,并使用WebApplicationContext集成web层即可。
当需要通过web服务访问现有代码时,可以使用Spring的Hessian-,Burlap-,Rmi-或者JaxRpcProxyFactory类,远程访问现有的应用并非难事。
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、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.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>4.3.0.RELEASEversion>
<scope>runtimescope>
dependency>
dependencies>
就这样,注意如果不需要编译Spring API,可以把scope声明为runtime,这是依赖注入使用的典型案例。
上面的示例使用Maven中央仓库,如果使用Spring的Maven仓库(例如,里程碑或开发快照),需要在Maven配置中指定仓库位置。
release版本:
<repositories>
<repository>
<id>io.spring.repo.maven.releaseid>
<url>http://repo.spring.io/release/url>
<snapshots><enabled>falseenabled>snapshots>
repository>
repositories>
里程碑版本:
<repositories>
<repository>
<id>io.spring.repo.maven.milestoneid>
<url>http://repo.spring.io/milestone/url>
<snapshots><enabled>falseenabled>snapshots>
repository>
repositories>
快照版本:
<repositories>
<repository>
<id>io.spring.repo.maven.snapshotid>
<url>http://repo.spring.io/snapshot/url>
<snapshots><enabled>trueenabled>snapshots>
repository>
repositories>
#####Maven的“物料清单式”依赖
使用Maven时可能会不小心混合了Spring不同版本的jar包。例如,你可能会发现第三方库或其它的Spring项目存在旧版本的传递依赖。如果没有明确地声明直接依赖,各种各样不可预料的情况将会出现。
为了解决这个问题,Maven提出了“物料清单式”(BOM)依赖的概念。可以在dependencyManagement部分导入spring-framework-bom以保证所有的Spring依赖(不管直接还是传递依赖)使用相同的版本。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-framework-bomartifactId>
<version>4.3.0.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
使用BOM的另外一个好处是不再需要指定**
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
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:
如下,在dependencyManagement中添加部分代码就可以排除掉commons-logging了:
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>4.3.0.RELEASEversion>
<exclusions>
<exclusion>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
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.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>4.3.0.RELEASEversion>
<exclusions>
<exclusion>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>jcl-over-slf4jartifactId>
<version>1.5.8version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.5.8version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.5.8version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.14version>
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.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>4.3.0.RELEASEversion>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.14version>
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 核心容器的改进
核心容器有以下几点改进:
###3.7 Web的改进
保留了Servlet 2.5服务器的部署,但Spring 4.0现在主要关注Servlet 3.0+环境的部署。如果使用Spring MVC测试框架,需要保证在test classpath上包含Servlet 3.0的兼容JAR包。
除了下面要讲的WebSocket方面的支持,在Spring的Web模块还包含以下几点改进:
###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还引入了几个新特性用于单元测试和集成测试:
##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合作使用:
最后,Spring 4.1还提供了以下各种各样的改进:
###4.2 缓存的改进
Spring 4.1支持JCache(JSR-107)注解,直接使用Spring已存在的缓存配置和基础架构即可,不需要其它的改变。
Spring 4.1也极大地改进了它的缓存策略:
Spring 4.1还为了添加putIfAbsent方法对CacheInterface做了重大改变。
###4.3 Web的改进
###4.4 WebSocket 消息处理的改进
###4.5 测试的改进
##5. Spring 4.2的新特性和增强功能
###5.1 核心容器的改进
public @interface ContextConfiguration {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
// ...
}
- 类似地,重写了元注解属性的注解现在也可以使用**@AliasFor**细粒度地控制那些在注解层次结构中被重写的属性。实际上,现在可以为元注解的**value**属性声明一个别名。 - 例如,现在可以像下面一样开发一种重写了自定义属性的组合注解。
Java
@ContextConfiguration
public @interface MyTestConfig {
@AliasFor(annotation = ContextConfiguration.class, attribute = "value")
String[] xmlFiles();
// ...
}
```
- 参考Spring注解编程模型。
###5.2 数据访问的改进
###5.3 JMS的改进
###5.4 Web的改进
###5.5 WebSocket消息处理的改进
###5.6 测试的改进
##6. Spring 4.3的新特性和增强功能
###6.1 核心容器的改进
###6.2 数据访问的改进
###6.3 缓存的改进
spring 4.3 允许并发调用给定的key,从而使得值只被计算一次。这是一项可选功能,通过**@Cacheable的新属性sync启用。这项功能也使Cache接口做了重大改变,增加了get(Object key, Callable
spring 4.3 也改进了以下缓存方面的内容:
###6.4 JMS的改进
###6.5 Web的改进
###6.6 WebSocket消息处理的改进
###6.7 测试的改进
###6.8 支持新库和服务器
另外,spring 4.3的spring-core.jar中集成了更新的ASM 5.1和Objenesis 2.4。
欢迎关注我的公众号“彤哥读源码”,查看更多“源码&架构&算法”系列文章, 与彤哥一起畅游源码的海洋。