第1章 Spring Boot史前简史
大约20年前,程序员们使用“企业级Java Bean”(EJB)开发企业应用,需要配置复杂的XML。
在二十世纪初期,新兴Java技术——Spring,横空出世。使用极简XML和POJO(普通Java对象),结合EJB的替代品(如Hibernate),Spring在企业级Java开发上占据了绝对领先地位。
但是,随着Spring的不断发展,当初的XML配置逐渐变得复杂庞大,成了累赘,遭众多程序员“诟病”。后来,Spring推出了JavaConfig项目,使用声明式的注解,大量减少了显式的XML配置。
然而,问题到这里,并没有结束。
1.1 J2EE(Java 2 Platform Enterprise Edition)简介
J2EE 的四层模型
J2EE使用多层的分布式应用模型,如下图所示:
应用逻辑按功能划分为组件,各个应用组件根据他们所在的层分布在不同的机器上。事实上,sun设计J2EE的初衷正是为了解决两层模式(client/server)的弊端,在传统模式中,客户端担当了过多的角色而显得臃肿。
J2EE平台由一整套服务(Services)、应用程序接口(APIs)和协议构成,它对开发基于Web的多层应用提供了功能支持。
如下是对J2EE中的13种技术规范进行简单的描述[3]:
JDBC(Java Database Connectivity): JDBC API为访问不同的数据库提供了一种统一的途径,象ODBC一样,JDBC对开发者屏蔽了一些细节问题,另外,JDCB对数据库的访问也具有平台无关性。
JNDI(Java Name and Directory Interface): JNDI API被用于执行名字和目录服务。它提供了一致的模型来存取和操作企业级的资源如DNS和LDAP,本地文件系统,或应用服务器中的对象。
EJB(Enterprise JavaBean): J2EE技术之所以赢得某体广泛重视的原因之一就是EJB。它们提供了一个框架来开发和实施分布式商务逻辑,由此很显著地简化了具有可伸缩性和高度复杂的企业级应用的开发。EJB规范定义了EJB组件在何时如何与它们的容器进行交互作用。容器负责提供公用的服务,例如目录服务、事务管理、安全性、资源缓冲池以及容错性。但这里值得注意的是,EJB并不是实现J2EE的唯一途径。正是由于J2EE的开放性,使得有的厂商能够以一种和EJB平行的方式来达到同样的目的。
RMI(Remote Method Invoke): 正如其名字所表示的那样,RMI协议调用远程对象上方法。它使用了序列化方式在客户端和服务器端传递数据。RMI是一种被EJB使用的更底层的协议。
Java IDL/CORBA: 在Java IDL的支持下,开发人员可以将Java和CORBA集成在一起。 他们可以创建Java对象并使之可在CORBA ORB中展开, 或者他们还可以创建Java类并作为和其它ORB一起展开的CORBA对象的客户。后一种方法提供了另外一种途径,通过它Java可以被用于将你的新的应用和旧的系统相集成。
JSP(Java Server Pages): JSP页面由HTML代码和嵌入其中的Java代码所组成。服务器在页面被客户端所请求以后对这些Java代码进行处理,然后将生成的HTML页面返回给客户端的浏览器。
Java Servlet: Servlet是一种小型的Java程序,它扩展了Web服务器的功能。作为一种服务器端的应用,当被请求时开始执行,这和CGI Perl脚本很相似。Servlet提供的功能大多与JSP类似,不过实现的方式不同。JSP通常是大多数HTML代码中嵌入少量的Java代码,而servlets全部由Java写成并且生成HTML。
XML(Extensible Markup Language): XML是一种可以用来定义其它标记语言的语言。它被用来在不同的商务过程中共享数据。XML的发展和Java是相互独立的,但是,它和Java具有的相同目标正是平台独立性。通过将Java和XML的组合,您可以得到一个完美的具有平台独立性的解决方案。
JMS(Java Message Service): MS是用于和面向消息的中间件相互通信的应用程序接口(API)。它既支持点对点的域,有支持发布/订阅(publish/subscribe)类型的域,并且提供对下列类型的支持:经认可的消息传递,事务型消息的传递,一致性消息和具有持久性的订阅者支持。JMS还提供了另一种方式来对您的应用与旧的后台系统相集成。
JTA(Java Transaction Architecture): JTA定义了一种标准的API,应用系统由此可以访问各种事务监控。
JTS(Java Transaction Service): JTS是CORBA OTS事务监控的基本的实现。JTS规定了事务管理器的实现方式。该事务管理器是在高层支持Java
Transaction API (JTA)规范,并且在较底层实现OMG OTS specification的Java映像。JTS事务管理器为应用服务器、资源管理器、独立的应用以及通信资源管理器提供了事务服务。JavaMail: JavaMail是用于存取邮件服务器的API,它提供了一套邮件服务器的抽象类。不仅支持SMTP服务器,也支持IMAP服务器。
JTA(JavaBeans Activation Framework): JavaMail利用JAF来处理MIME编码的邮件附件。MIME的字节流可以被转换成Java对象,或者转换自Java对象。大多数应用都可以不需要直接使用JAF。
J2EE提供了"编写一次、随处运行"的特性、方便存取数据库的JDBC API、CORBA技术以及能够在Internet应用中保护数据的安全模式等等,同时还提供了对 EJB(Enterprise JavaBeans)、Java Servlets API、JSP(Java Server Pages)以及XML(标准通用标记语言的子集)技术的全面支持。
1.2 Java企业级开发框架概述
EJB(Enterprise Java Bean)
曾几何时,EJB被人们当做J2EE的核心而顶礼膜拜。
EJB就是把原来放到客户端实现的代码放到服务器端,并依靠RMI(Remote Method Invocation,是EJB的 技术基础)进行通信。而客户端就单纯负责发送调用请求和显示处理结果。
在J2EE 中,这个运行在一个独立的服务器上,并封装了业务逻辑的组件就EJB组件。
回顾EJB出现以前的Java应用开发,大部分开发者直接用JSP页面,再加上少量Java Bean就可以完成整个应用,所有的业务逻辑、数据库访问逻辑都直接写在JSP页面中。系统开发前期,开发者不会意识到有什么问题,但随着开发进行到后期,应用越来越大,开发者需要花费大量时间去解决非常常见的系统级问题,反而无暇顾及真正需要解决的业务逻辑问题。
对于EJB来说,它提供了一种良好的组件封装,EJB容器负责处理如事务、访问控制等系统级问题,而EJB开发者则集中精力去实现业务逻辑;对页面开发者而言,EJB的存在无须关心,EJB的实现无须关心,他们只要调用EJB的方法即可。
基于EJB的程序架构总体有一个非常优秀的思想:业务逻辑相关的实现集中在EJB中完成,而EJB容器则负责提供带有重复性质的、系统级的功能,这样EJB组件就可对外提供完整的业务服务。
但是,由于EJB开发的复杂性,导致许多开发者的批评,以致后来直接催生了spring框架。Spring容器管理的不再是复杂的EJB组件,而是POJO(Plain Old Java Object) Bean。Spring容器取代了原有的EJB容器,以Spring框架为核心的应用无须EJB容器支持,可以直接在Web容器中运行。
现在SSH(Spring + Struts + Hibernate)是越来越少了,现在比较通用的是SSM(Spring + SpringMVC + Mybatis)。
在SSH框架中,Spring负责容器管理,对象生命周期的管理以及对象关系的维护。Hibernate负责持久层,它将JDBC做了一个良好的封装,程序员在与数据库进行交互时可以不用书写大量的SQL语句。Struts是在应用层,它负责调用serivce业务逻辑层。
Struts
为了解决这些问题,出现了Struts框架,它是一个完美的MVC实现,它有一个中央控制类(一个Servlet),针对不同的业务,我们需要一个Action类负责页面跳转和后台逻辑运算,一个或几个JSP页面负责数据的输入和输出显示,还有一个Form类负责传递Action和JSP中间的数据。JSP中可以使用Struts框架提供的一组标签,就像使用HTML标签一样简单,但是可以完成非常复杂的逻辑。从此JSP页面中不需要出现一行<%%>包围的Java代码了。
可是所有的运算逻辑都放在Struts的Action里将使得Action类复用度低和逻辑混乱,所以通常人们会把整个Web应用程序分为三层,Struts负责显示层,它调用业务层完成运算逻辑,业务层再调用持久层完成数据库的读写。
使用JDBC连接来读写数据库,我们最常见的就是打开数据库连接、使用复杂的SQL语句进行读写、关闭连接,获得的数据又需要转换或封装后往外传,这是一个非常烦琐的过程。
Hibernate
这时出现了Hibernate框架。它对JDBC提供了封装。Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL的自动生成和执行。
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。[8]
现在我们有三个层了,可是每层之间的调用是怎样的呢?比如显示层的Struts需要调用一个业务类,就需要new一个业务类出来,然后使用;业务层需要调用持久层的类,也需要new一个持久层类出来用。通过这种new的方式互相调用就是软件开发中最糟糕设计的体现。简单的说,就是调用者依赖被调用者,它们之间形成了强耦合,如果我想在其他地方复用某个类,则这个类依赖的其他类也需要包含。程序就变得很混乱,每个类互相依赖互相调用,复用度极低。如果一个类做了修改,则依赖它的很多类都会受到牵连。 为此,出现了Spring框架。
Mybatis
MyBatis是另外一个广泛使用的ORM框架。原本是Apache的一个开源项目iBatis, 后改名为MyBatis 。MyBatis的核心在于管理 POJO 与 SQL 之间的映射关系。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
Mybatis框架的架构如下图:
MyBatis相对于Hibernate,主要优势是可以进行更为细致的SQL优化。
关于MyBatis,详细了解可参考:http://www.mybatis.org/mybatis-3/zh/index.html
Spring框架
Spring Framework:
Core support for dependency injection, transaction management, web applications, data access, messaging, testing and more.
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(全栈式) 轻量级开源框架。
循证架构(Evidence-Based Architecture)
Rod Johnson在2002年编著的《Expert one on one J2EE design and development》一书中,对Java EE 系统框架臃肿、低效、脱离现实的种种现状提出了质疑,并积极寻求探索革新之道。以此书为指导思想,他编写了interface21框架,这是一个力图冲破J2EE传统开发的困境,从实际需求出发,着眼于轻便、灵巧,易于开发、测试和部署的轻量级开发框架。
Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。同年他又推出了一部堪称经典的力作《Expert one-on-one J2EE Development without EJB》,该书在Java世界掀起了轩然大波,不断改变着Java开发者程序设计和开发的思考方式。
没有最好的架构,只有最合适的架构。循证架构是《Expert One-on-One J2EE Development without EJB》(Rod Johnson,)一书中推崇的架构思路,用俺们的话说就是摸着石头过河,找最适合自己的架构。
我们曾经在无数的书籍和文章中看到,EJB是J2EE的核心技术之一。而Rod Johnson竟然宣称,绝大多数的J2EE应用根本不需要EJB。
Rod Johnson引领了一场J2EE领域影响深远的变革。Spring和Hibernate,IoC和AOP,轻量级架构等等。还有更重要的一点,是遵循一切实事求是的“循证架构”的问题解决的方法论哲学。
Rod Johnson认为,应该是基于实践的证据、来自历史项目或亲自试验的经验,而不是任何形式的偶像崇拜或者门户之见。[10]
“循证哲学”(基于实践的证据、来自历史项目或亲自试验的经验)、“实事求是”的工作方式——这原本就应该是程序员的工作方式。
“认识来源于实践,而又运用于实践”。
——马克思
人的认识来源于实践,是随着实践的发展而发展的。通过实践得出的认识,只有作用于实践并通过实践的检验,才能够确定认识的正确与否。
循证架构思想来源于”循证实践“。任何涉及模式,架构模式,编程范式(过程式,面向对象式,函数式,逻辑式,面向服务式)的问题,都是基于解决某个实际业务场景才有其实质存在的意义。
循证实践(Evidence-Based Practise),亦为循证学。本意是"基于证据的实践",其理念始于20世纪末发展起来的循证医学。最初意指医生"将当前所能获得的最佳研究证据与自身的专业技能及患者的价值观整合起来进行治疗"。此后,它便以迅雷不及掩耳之势席卷了整个医疗卫生领域,并不断向邻近学科渗透,形成了循证心理治疗、循证教育学、循证社会学等数十个新的学科领域。
在程序开发里不同模块之间信息的沟通是通过对象传递完成的,而对象能否顺利传递就是要合理的构建好对象,而管理好对象的构建方式就能管理好对象传递,spring主要就是解决这个问题的。spring提供一个容器,我们在xml文件里,或者通过注解的方式(注解的方式是通过反射机制实现)定义各个对象的依赖关系,由容器完成对象的生命周期的管理(创建,运行,销毁)。
Spring框架建立在IOC和AOP技术之上。
IOC: Inversion of Control,控制反转,就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控。 当我们的代码里需要使用某个实例的时候就可以直接从容器里获取。对象的实例化由spring容器负责搞定,所以它被称为控制反转,控制反转的意思就是本来属于java程序里构建对象的功能交由容器接管,依赖注入(DI)就是当程序要使用某个对象时候,容器会把它注入到程序里。Spring IOC有三种注入方式:接口注入、setter注入、构造器注入。
AOP: Aspect Oriented Programming,面向切面编程,就是把可重用的功能提取出来,然后将这些通用功能在合适的时候织入到应用程序中,比如事务管理、权限控制、日志记录、性能统计等。通过预编译方式和运行期动态代理实现业务逻辑模块之间的隔离,使业务逻辑模块间的耦合度极大化地降低,提高程序可重用性和开发的效率。使用 AOP 后,公共服务 (比 如日志、持久性、事务等)就可以分解成方面并应用到域对象上,同时不会增加域对象的对象模型的复杂性。AOP的工作模式如下图所示:
1.3 Spring生态系统
Spring的整体架构
Spring框架至今已集成了20多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块[5]:
Core Container
核心部分分为4大块,spring-core, spring-beans, spring-context, spring-expression. 其中core和bean是整个框架的核心,提供了基础的DI和IoC功能。 Context建立在core和beans模块之上,提供一种类似JNDI且以框架的方式来操作对象的方式。Context模块从beans模块继承它的功能同时增加了国际化支持,如资源绑定等,同时,Context模块也支持JavaEE功能,如EJB,JMX和基本的远程调用。ApplicationContext接口是context模块的焦点。expression是一种很强大的expression language,支持在运行时查询和操作对象的属性,我们会在后面的文章中举些例子来说明spring expression language的用法。
AOP and instrumentation
Aop模块提供了面向切面编程的实现,和AspectJ集成。
Messaging
Messaging是spring4新增加的模块,包含了一部分主要的基于message的应用的实现。
Data Access/Integration
Data access顾名思义,是spring对数据层提供的支持,是功能比较丰富的模块。提供了包括JDBC,事物,ORM,JMS等一系列实现。
Web
Web模块主要提供面向web的一些实现,例如多文件上传,servlet监听器以及spring mvc方面的支持。
Test
Test模块主要是针对spring的各个模块做各种各样的测试,包括单元测试、集成测试等等。
1.4 Spring JavaConfig
Java元编程 (meta-programming)
一般代码的操作对象是数据。元编程操作的对象是代码。
元编程一言以蔽之,就是用代码生成(操纵)代码。在运行时创建和修改代码而非编程时,这种程序叫做元程序。而编写这种程序就叫做元编程。元编程是用代码在编译期或运行期生成/改变代码。元编程是现实世界的抽象的利器。
元编程技术在多种编程语言中都可以使用,但更多的还是被应用于动态语言中,因为动态语言提供了更多的在运行时将代码视为数据进行操纵的能力。
Java 5中提供了Annotations,它是Java的metadata。Java应用中的元数据在早期Java版本中,一般使用属性文件、XML,后来注解出现了,就都用注解了。
Java通过反射机制实现元编程。反射是促进元编程的一种很有价值的语言特性。
常见的开发语言均能做到元编程,Lisp就不用多说了,C的Marco,C++的Template,Java的Annotation,C#的Attribute、Reflection、CodeDom和IL Emitter,各种脚本语言(如js、python)的eval,甚至连Unix/Linux的shell脚本也能。
元编程常见的应用场景很多,扩展语法、开发DSL、生成代码、根据特定场景自动选择代码优化、解决一些正交的架构设计问题、AOP等等。
元编程,是对语言自身再向上一层抽象。
JavaConfig简介
Spring IOC有一个非常核心的概念——Bean。由Spring容器来负责对Bean的实例化,装配和管理。XML是用来描述Bean最为流行的配置方式。Spring可以从XML配置文件中读取任何类型的元数据并自动转换成相应的Java代码。Spring改变了java的编程模式。
随着Spring的日益发展,越来越多的人对Spring提出了批评。“Spring项目大量的烂用XML”就是最为严励的一个批评。由于Spring会把几乎所有的业务类都以Bean的形式配置在XML文件中,造成了大量的XML文件。使用XML来配置Bean失去了编译时的类型安全检查。大量的XML配置使得整个项目变得更加复杂。Rod Johnson也注意到了这个非常严重的问题。
当随着Java EE 5.0的发布,其中引入了一个非常重要的特性——Annotations(注解)。注解是源代码的标签,这些标签可以在源代码层进行处理或通过编译器把它熔入到class文件中。在Java EE 5以后的版本中,注释成为了一个主要的配置选项。Spring使用注释来描述Bean的配置与采用XML相比,因类注释是在一个类源代码中,可以获得类型安全检查的好处。可以良好的支持重构。
JavaConfig就是使用注释来描述Bean配置的组件。JavaConfig 是Spring的一个子项目(详细了解可参考:http://docs.spring.io/spring-javaconfig/docs/).
JavaConfig与注解驱动配置( Annotation-Driven Configuration)
后来,当@Annotation出现了,大部分技术、框架就纷纷放弃了XML配置文件,改为使用Annotation来管理配置信息。
Spring有2种常用的配置方式:
- 基于XML文件的配置
- 基于@Annotation的配置
Spring的XML配置方式是使用被Spring命名空间的所支持的一系列的XML标签来实现的。Spring有以下主要的命名空间:context、beans、jdbc、tx、aop、mvc等。
使用XML来配置Bean所能实现的功能,通过JavaConfig同样可以很好的实现。之前我们都是在xml文件中定义bean的,比如:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloBean" class="com.hello.impl.HelloWorldImpl">
</beans>
其实我们可以使用注解来完成这些事情,例如下面的代码,完成的功能和上面的xml配置的功能是一样的:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.hello.HelloWorld;
import com.hello.impl.HelloWorldImpl;
@Configuration
public class AppConfig {
@Bean(name="helloBean")
public HelloWorld helloWorld() {
return new HelloWorldImpl();
}
}
使用@Bean注解,来标识此方法构造出一个由Spring容器管理的bean。Spring对Java配置的支持是由@Configuration注解和@Bean注解来实现的。由@Bean注解的方法将会实例化、配置和初始化一个新对象,这个对象将由Spring的IoC容器来管理。@Bean声明所起到的作用与<bean/> 元素类似。被@Configuration所注解的类则表示这个类的主要目的是作为bean定义的资源。被@Configuration声明的类可以通过在同一个类的内部调用@bean方法来设置嵌入bean的依赖关系。
一般在一个大型工程项目中,如果将所有的bean都配置在一个xml文件中,那么这个文件就会非常的大。所以一般会将一个大的xml配置文件分割为好几份。这样方便管理,最后在总的那个xml文件中导入。比如:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="config/customer.xml"/>
<import resource="config/scheduler.xml"/>
</beans>
但是现在我们也可以使用JavaConfig来完成同样的工作了:
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({ CustomerConfig.class, SchedulerConfig.class })
public class AppConfig {
}
@Configuration可以被认为是相当于XML的< bean / >元素。
Spring在2.5版本以后开始支持用注解的方式来配置依赖注入。可以用注解的方式来替代XML方式的bean描述,可以将bean描述转移到组件类的内部,只需要在相关类上、方法上或者字段声明上使用注解即可。使用JavaConfig的配置方式,一行XML代码都不需要,什么web.xml,Application-context.xml,Beans.xml,统统再见。
在 Spring XML中, 启动注解注入bean,通过如下标签实现:
<context:annotation-config/>
在 JavaConfig中, 等同于 @AnnotationDrivenConfig注解。
代码示例:
@Configuration
@AnnotationDrivenConfig
public class Config {
// may now use @Autowired to reference beans from other @Configuration classes, XML, etc
}
使用@ComponentScan注解,等同于在 Spring XML中的
<context:component-scan/>
代码示例:
package com.company.foo;
@Service
public class FooServiceImpl implements FooService {
private final FooRepository fooRepository;
@Autowired
public FooService(FooRepository fooRepository) {
this.fooRepository = fooRepository;
}
// ...
}
package com.company.foo;
@Repository
public class JdbcFooRepository implements FooRepository {
private final DataSource dataSource;
@Autowired
public FooRepository(DataSource dataSource) {
this.dataSource = dataSource;
}
// ...
}
@Configuration
@ComponentScan("com.company") // search the com.company package for @Component classes
@ImportXml("classpath:com/company/data-access-config.xml") // XML with DataSource bean
public class Config {
}
在配置类中使用上述的配置,我们就可以在代码里调用service方法了:
public class Main {
public static void main(String[] args) {
JavaConfigApplicationContext ctx = new JavaConfigApplicationContext(Config.class);
FooService fooService = ctx.getBean(FooService.class);
fooService.doStuff();
}
}
小结
Spring框架项目的出发点是为了解决被其他框架所忽略的部分。在J2EE各个具体领域,都有很多出色的解决方案,web框架持久化方案,远程调用工具等等,然而将这些工具整合成一个全面的架构,却困难重重,甚至成为一种负担。spring提供了一个完整的解决方案,将各种专用框架整合成一个连贯的整体的架构。
Spring诞生之初,就是为了解决当初EJB的重量级复杂编程问题。Spring通过轻量级的架构,使用IOC(DI)和AOP,用POJO实现了EJB的功能。可是,Spring令人头疼的繁杂的配置,让开发者陷入了另一个深渊(世间万物,往往如此)。一开始,Spring使用大量xml配置。Spring 2.5引入了基于注解的组件扫描,消除了大量针对应用自身的组件的xml配置。Spring 3.0 有了Java Config解决方案,可以替代xml。但是,还是有使用很多Spring的特性,诸如事务管理,SpringMVC,以及集成第三方框架的时候(比如模板引擎:velocity, freemarker, thymeleaf),还是需要大量的显式配置。配置Servlet和Filter等同样需要在web.xml里面配置。[9]
对了,还有运行调试的时候,需要配置web容器等大量手工劳动。
这些配置,耗去了程序员们的大量的精力和时间,使得生产效率大减折扣。程序员们的大脑不得不在编写业务逻辑代码跟xml配置之间来回切换。
在后面的章节中,我们将看到Spring Boot对程序员更加简易地使用Spring框架上面所带来的巨大变化,以及对Spring生态体系,各种技术框架的的整合集成。
参考资料
- http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/
- https://docs.spring.io/spring/docs/current/javadoc-api/
- https://www.ibm.com/developerworks/cn/java/j2ee/
- http://baike.baidu.com/item/spring/85061
- http://howtodoinjava.com/spring/spring-core/top-spring-core-interview-questions-with-answers/
- http://howtodoinjava.com/java-spring-framework-tutorials/
- http://baike.baidu.com/item/MyBatis
- http://baike.baidu.com/item/Hibernate/206989
- 《Spring Boot In Action》(Craig Walls)
- 《Expert one on one J2EE design and development》(Rod Johnson)