Spring框架是一个轻量级解决方案,也是构建企业级应用的潜在一站式服务。然而,Spring的模块化容许你只使用你须要的部分,而没必要所有引入。你可使用IOC容器搭配其余web框架,也能够集成Hibernate或JDBC抽象层。Spring框架支持声明式事务管理,和经过RMI或web services进行远程访问,以及持久化数据的多种选择。它还提供了一个全功能的MVC框架,同时支持透明的AOP配置。html
Spring的设计是非侵入式的,意味着在集成层(如数据访问层)你自己的逻辑代码一般不用依赖框架自己,但对数据访问技术和Spring库的一些依赖不可避免。然而这些依赖能够同你的逻辑代码轻易地隔离开。前端
本文档是Spring框架功能的参考指南。若是你对本文档有任何要求,意见或问题,能够发送到用户邮箱列表。关于框架的问题能够访问StackOverflow(https://spring.io/questions);java
这篇参考指南提供了关于Spring框架的详细信息,是包含全部功能的综合文档,以及Spring所拥护的基本概念(如依赖注入)的一些背景知识。web
若是你刚接触Spring,能够经过建立一个Spring Boot应用来开始使用Spring框架。Spring Boot提供了一种快速的(和全配置的)方式来建立一个生产级的Spring应用。它基于Spring框架,遵循一些配置惯例,旨在让你的应用快速运行起来。算法
你可使用start.spring.io来生成一个基本的工程,或者参考入门指南中一个,好比构建RESTful Web Service入门。除了很容器理解,这些指南都是任务方式的,其中大部分也都是基于Spring Boot的。它们还涵盖了Spring解决方案中你可能考虑解决特定问题的其余项目。spring
Spring框架是一个Java平台,为开发Java应用程序提供全面的基础设施支持。Spring接管了基础设施,以便你能够专一于你的应用。数据库
Spring使你可以使用普通的Java对象(POJO)构建应用程序,并将企业服务非侵入式地应用于POJO。此功能适用于Java SE编程模型以及完整和部分Java EE。express
做为一个应用开发着,你能够从Spring平台受益如下内容:apache
Java应用程序——从受限的嵌入式应用程序到n层服务器端企业应用程序运行范围的宽松术语一般由协做造成应用程序的对象组成。于是应用程序中的对象互相依赖。编程
虽然Java平台提供了丰富的应用程序开发功能,但它缺少将基本组织成总体的方法,将该任务留给架构师和开发人员。虽然你可使用工厂(Factory),抽象工厂(Abstract Factory),建造者(Builder),装饰器(Decorator),服务定位(Service Locator)等设计模式来组合构成应用程序的各类类和对象实例,但这些模式只有简单的说明:模式的名称,描述,应用于哪里以及能解决哪一种问题等等。而你必须本身在应用中将模式的最佳实践付诸实施。
Spring框架控制反转(IOC)组件提供将不一样组件组成完整的可以使用的应用程序的实践方法。 Spring框架将形式化的设计模式做为首要的对象集成到应用程序进行编译。许多组织机构以这种方式使用Spring框架来设计强大的可维护的应用程序。
背景知识 Martin Fowler2004年在他的网站中提出关于控制反转(IOC)的问题:"问题是,反转的是什么方面的控制"。Fowler建议从新命名规则,使其更加自明,并提出依赖注入。
Spring框架由大约20个模块功能组成,这些模块能够分红核心容器(Core Container),数据访问/集成(Data Access/Integration),Web,AOP(Aspect Oriented Programming),设备(Instrumentation)、,消息发送(Messaging),和测试(Test)几个部分,具体以下图所示。
如下部分列出了每一个功能的可用模块同产品名称及其涵盖的主题。产品名称与依赖管理工具(Dependency Management tools)的产品id相关联。
核心容器由spring-core
,spring-beans
,spring-context
,spring-context-support
,和spring-expression
(Spring表达式语言)模块组成。
spring-core
和spring-beans
模块提供了框架的基础部分,包含控制反转和依赖注入。BeanFactory
是工厂模式的一个复杂实现。它消除了对单例编程化的须要并容许你将依赖关系的配置和规范与实际程序逻辑相分离。
上下文(spring-context
)模块创建在由Core和Beans模块提供的实体基础上:它是以相似JNDI注册表的框架式方式访问对象的一种手段。上下文模块从Beans模块继承其功能,并增长对国际化的支持(如使用资源组),事件传播,资源加载和上下文的透明建立,好比Servlet容器。上下文模块也支持JavaEE的功能,诸如EJB,JMX和基本远程调用。ApplicationContext接口是上下文模块的焦点。spring-context-support
支持常见的第三方库集成到Spring应用程序环境中,特别是缓存(EhCache,JCache)和调度(CommonJ,Quartz)。
spring-expression
模块提供了强大的表达式语言,用于在运行时查询和操做对象图。它是JSP2.1规范中规定的统一表达语言(统一EL)的扩展。该语言支持设置和获取属性值,属性分配,方式调用,访问数组,集合和索引器的内容,逻辑和算术运算符,命名变量以及从Spring的IOC容器中以名称检索对象。它还支持列表投影和选择以及常见列表聚合。
spring-aop
模块提供了符合AOP联盟的面向切面编程的实现,容许你定义方法拦截器和切入点,以便干净地解除那些实现了应该分离的功能的代码。使用源码级元数据功能,你还能够将行为信息合并到代码中,相似于.NET的属性的方式。
单独的spring-aspects
模块提供与AspectJ的集成。
spring-instrument
模块提供了类级别的设备支持和能够在某些应用服务里使用的类加载器级别的实现。spring-instrument-tomcat
模块包含了Tomcat的spring设备代理。
Spring4框架包含一个spring-messaging
模块,其中包含来自Spring Integration项目(如Message
,MessageChannel
,MessageHandler
)的关键抽象,以及基于消息的应用的基础的其余部分。模块还包含了映射消息到方法的注解集合,相似Spring MVC基于编程方式的注解。
数据访问/集成层包含了JDBC、ORM、OXM、JMS和事务模块。
spring-jdbc
模块提供了JDBC抽象层,再也不须要处理繁杂的JDBC编码以及数据库供应商特定错误码的解析。
spring-tx
模块支持为实现指定接口的类以及全部POJOs(普通Java对象)的编程和声明式事务管理。
spring-orm
模块为流行的对象关系映射APIs提供集成层,包括JPA和Hibernate。经过spring-orm
模块,你能够将O/R映射框架组合Spring提供的其余功能一块儿使用,好比前面说起的简单声明式事务管理功能。
spring-oxm
模块为Object/XML映射实现提供抽象层,诸如JAXB,Castor,JiBX和XStream。
spring-jms
模块(Java消息服务)包含生产和消费消息的功能。从Spring框架4.1版本开始,它提供与spring-messaging
模块的集成。
Web层包含spring-web
,spring-webmvc
和spring-websocket
模块。
spring-web
模块提供基础的面向web的集成功能,支持多文件上传功能,以及经过Servlet监听器和面向web的应用上下文初始化IOC容器。同时还包含HTTP客户端和Spring远程支持的web相关部分。
spring-webmvc
模块(也称为Web-Servlet模块)包含支持web应用的Spring模型-试图-控制(MVC)和REST风格的web服务实现。Spring的MVC框架提供了域模型代码(domain model code)和Web表单的清晰分离,并与Spring框架全部其余功能相集成。
spring-test
模块支持使用JUnit或TestNG进行Spring组件的单元测试或集成测试。它提供了Spring ApplicationContexts的一致加载和缓存。同时提供用于隔离测试的模拟对象(mock objects)。
前面描述的构件块使得Spring成为许多场景中的合理选择,从在资源受限设备上运行的嵌入式应用程序到使用Spring事务管理功能和Web框架集成的全面的企业应用程序。
图2.2 典型的成熟的Spring web应用程序
Spring的声明式事务管理功能支持web应用程序全事务化,就同你使用EJB容器管理的事务同样。全部你的定制业务逻辑均可以由简单的POJOs实现,并由Spring IoC容器管理。其余服务包括发送email和独立于web层的校验,而你能够选择何处去执行校验规则。Spring的ORM支持同JPA和Hibernate的整合,好比,当你使用Hibernate时,能够保持原有的映射文件及标准Hibernate SessionFactory
配置。表单控制器无缝整合了web层和域模型,无需那些转换HTTP参数到域模型的ActionForms
或其余类。
图2.3 Spring中间层使用第三方web框架
有时状况并不容许你彻底切换到一个不一样的框架。Spring框架不是一个要么使用所有特性要么什么都用不了的解决方案,不强制使用其中的每一个功能。现存的前端如Struts,Tapestry,JSF或其余UI框架均可以同基于Spring的中间层整合在一块儿,从而使你能过使用Spring事务功能。你只须要使用ApplicationContext
链接你的业务逻辑以及经过WebApplicationContext
整合你的web层。
图2.4 远程调用使用场景
你可使用Spring的Hessian-
,Rmi-
或HttpInvokerProxyFactoryBean
类来经过web服务访问现存的代码。远程访问现存应用程序并不困难。
图2.5 EJBs-包装现存POJOs
Spring框架还为企业JavaBeans提供了一个访问抽象层,使你可以重用现有的POJO,并将其包装在无状态会话bean中,以便在可能须要声名式安全的可扩展,故障安全的web应用程序中使用。
依赖管理不一样于依赖注入。要在你的应用程序中使用Spring的这些功能(好比依赖注入),须要 组合须要的库(jar包),并在运行时将其置于classpath下,编译时也尽量这样作。这些依赖并非要注入的虚拟组件,而是文件系统中的资源(一般状况下)。依赖管理的过程包括资源定位,资源存储并将其置于classpath。依赖多是直接的(好比运行时应用依赖于Spring的)和间接的(如应用中依赖commons-dbcp,而它又依赖于commons-pool)。间接的依赖每每是“过渡的”,而这些依赖是最难去识别和管理的。
若是你将要使用Spring,你须要拷贝一份包含你所须要的Spring部分的jar包。为了让这种操做更加容易,Spring被打包成一组模块,而且尽量地分离依赖关系,于是好比当你不想写一个web应用程序时,就没必要用spring-web模块。在本指南中引用Spring库模块,咱们使用简要命名约定spring-*
或者spring-*.jar
,*表明模块的简写(如spring-core
,spring-webmvc
,spring-jms
等)。你使用的真实jar包文件名一般是模块名拼上版本号(如spring-core-5.0.0.M5.jar)。
Spring框架的每一个release版都会发布到如下地方:
spring-*-<version>.jar
的形式,而Maven groupId是org.springframework
。所以你须要决定的第一件事就是怎么管理你的依赖:咱们一般推荐使用自动化系统,好比Maven,Gradle或Ivy,可是你也能够手工下载全部jar包。
你将在下面找到Spring的工件列表。更多详细的模块描述,请见2.2节模块。
表2.1.Spring框架工件
GroupId | ArtifactId | Description |
---|---|---|
org.springframework | spring-aop | 基于代理的AOP支持 |
org.springframework | spring-aspects | 基于AspectJ的面向切面 |
org.springframework | spring-beans | Beans支持,包括Groovy |
org.springframework | spring-context | 运行时应用上下文,包括调度和远程抽象 |
org.springframework | spring-context-support | 支持类将经常使用第三方库集成到Spring应用程序上下文中 |
org.springframework | spring-core | 核心工具,被许多其余Spring模块所依赖 |
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 | Spring组件的单元测试和集成测试支持 |
org.springframework | spring-tx | 事务基础设施,包含DAO支持和JCA整合 |
org.springframework | spring-web | Web支持包,包含客户端和web远程调用 |
org.springframework | spring-webmvc | REST风格web服务和web应用的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>5.0.0.M5</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的多个版本是颇有可能的。好比,你可能发现一个第三方库或其余的Spring工程,引用了一个旧版本。若是你忘记明确地声明依赖版本,各类意想不到的问题就会出现。
为了解决此类问题,Maven提供了“物料清单”(BOM)依赖的概念。你能够在dependencyManagement
块中导入spring-framework-bom
,来确保全部spring依赖(直接或间接的)都处于同一版本中。
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-framework-bom</artifactId> <version>5.0.0.M5</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
使用BOM的另外的好处是当你依赖于Spring框架时,没必要再指定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() // 可选的 maven { url "http://repo.spring.io/release" } }
你能够根据须要改变repositories
的URL,从/release
到/milestone
或/snapshot
。资源库配置后,你可使用一般的Gradle方式声明依赖:
dependencies { compile("org.springframework:spring-context:5.0.0.M5") testCompile("org.springframework:spring-test:5.0.0.M5") }
若是你喜欢使用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="5.0.0.M5" conf="compile->runtime"/>
尽管使用支持依赖管理的构建系统来获取Spring是推荐的方式,然而也能够直接下载分发的Zip文件。
分发zip包被发布在Spring的Maven库中。(这只是咱们图方便的方式,没必要经过Maven或其余构建系统来下载它)。
要下载一个分发zip包,打开浏览器访问http://repo.spring.io/release/org/springframework/spring ,选择适合版本的子文件夹。分发文件以-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的一个模块明确地依赖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:
spring-core
模块中排除这个依赖(由于这是惟一明确依赖commons-logging
的模块)commons-logging
替换成一个空的jar包,而后依赖这个特殊的commons-logging
(详细见SLF4J FAQ)要排除commons-logging,在你的dependencyManagement
块中增长如下内容:
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.0.0.M5</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的明确绑定。你须要提供几个依赖(以及排除已存在的commons-logging
):Log4j的SLF4J实现桥梁和Log4j实现本身。Maven中你能够配置以下:
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.0.0.M5</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.7.22</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version> </dependency> </dependencies>
看上去获取一些日志须要配置不少依赖。是的,可是可选的。对于类加载器问题,它应该比vanilla commons-logging
更好,特别是若是你处于像OSGi平台这样的严格容器中。 据称它有更好的性能,由于它的绑定做用于编译期而非运行时。
一种相对于SLF4J用户更经常使用的选择是直接绑定到Logback,使用更少的步骤和产生更少的依赖。因为Logback直接实现了SLF4J,因此移除了额外的绑定步骤,你只须要依赖于两个库而再也不是四个(jcl-over-slf4j
和logback
)。若是你这样作,你须要从其余外部的依赖(非Spring)排除slf4j-api依赖,由于你但愿classpath上的API只有一个version。
Log4j 1.x项目结束了,接下来应用的是Log4j 2
不少人使用Log4j做为配置和管理日志的框架。它高效且成熟,实际上咱们在编译和测试Spring的运行时也在使用。Spring也提供配置和初始化Log4j的一些工具,在一些模块有可选的Log4j编译期依赖。
想经过JCL使用Log4j,全部你要作的就是将Log4j放到classpath下并提供一个配置文件(log4j2.xml,log4j2.properties或其余支持的配置格式)。对于Maven用户,最简要的配置以下:
<dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-jcl</artifactId> <version>2.7</version> </dependency> </dependencies>
若是你但愿使用SLF4J,下面的依赖也须要:
<dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.7</version> </dependency> </dependencies>
下面是控制台日志配置的log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </Appenders> <Loggers> <Logger name="org.springframework.beans.factory" level="DEBUG"/> <Root level="error"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
许多人在其自己提供JCL实现的容器中运行他们的Spring应用程序。IBM Websphere应用服务器(WAS)就是这样。这每每引发问题,不幸的是没有终极解决方案;大多数状况下,简单地从你的应用中排除commons-logging是不够的。
要清楚一点:报告的问题一般不是与JCL自己相关,甚至和commons-logging也没有关系,而是与commons-logging绑定到另外一个框架(一般是Log4j)有关。由于commons-logging更改了一些容器中的旧版本(1.0)和大多数人如今使用的现代版本(1.1)之间执行运行时发现的方式可能会致使失败。Spring不使用JCL API的任何非通用部分,因此不会有什么问题。可是一旦Spring或你的应用尝试执行任何日志记录,你会发现与Log4j的绑定不生效。
这种状况下,使用WAS最简单的方法是反转类加载器层次结构(IBM称为“parent last”),以便应用控制JCL依赖关系,而非容器。该选项并不老是开放的,但在公共领域还有喝多其余建议可供选择,你的方案可能因容器的确切版本和功能集而不一样。