Spring 的前世今生
相信经历过不使用框架开发 Web 项目的 70 后、80 后都会有如此感触,如今的程序员开发项目太轻松
了,基本只需要关心业务如何实现,通用技术问题只需要集成框架便可。早在 2007 年,一个基于 Java
语言的开源框架正式发布,取了一个非常有活力且美好的名字,叫做 Spring。它是一个开源的轻量级
Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程
序开发。应用程序是由一组相互协作的对象组成。而在传统应用程序开发中,一个完整的应用是由一组
相互协作的对象组成。所以开发一个应用除了要开发业务逻辑之外,最多的是关注如何使这些对象协作
来完成所需功能,而且要低耦合、高聚合。业务逻辑开发是不可避免的,那如果有个框架出来帮我们来
创建对象及管理这些对象之间的依赖关系。可能有人说了,比如“抽象工厂、工厂方法模式”不也可以
帮我们创建对象,“生成器模式”帮我们处理对象间的依赖关系,不也能完成这些功能吗?可是这些又
需要我们创建另一些工厂类、生成器类,我们又要而外管理这些类,增加了我们的负担,如果能有种通
过配置方式来创建对象,管理对象之间依赖关系,我们不需要通过工厂和生成器来创建及管理对象之间
的依赖关系,这样我们是不是减少了许多工作,加速了开发,能节省出很多时间来干其他事。Spring
框架刚出来时主要就是来完成这个功能。
Spring 框架除了帮我们管理对象及其依赖关系,还提供像通用日志记录、性能统计、安全控制、异常处
理等面向切面的能力,还能帮我管理最头疼的数据库事务,本身提供了一套简单的 JDBC 访问实现,提
供与第三方数据访问框架集成(如 Hibernate、JPA),与各种 Java EE 技术整合(如 Java Mail、任务
调度等等),提供一套自己的 Web 层框架 Spring MVC、而且还能非常简单的与第三方 Web 框架集成。
从这里我们可以认为 Spring 是一个超级粘合大平台,除了自己提供功能外,还提供粘合其他技术和框
架的能力,从而使我们可以更自由的选择到底使用什么技术进行开发。而且不管是 JAVA SE(C/S 架构)
应用程序还是 JAVA EE(B/S 架构)应用程序都可以使用这个平台进行开发。如今的 Spring 已经不再
是一个框架,早已成为了一种生态。SpringBoot 的便捷式开发实现了零配置,SpringCloud 全家桶,
提供了非常方便的解决方案。接下来,让我们来深入探讨 Spring 到底能给我们带来什么?
一切从 Bean 开始
说到 Bean 这个概念,还得从 Java 的起源说起。早在 1996 年,Java 还只是一个新兴的、初出茅庐的
编程语言。人们之所以关注她仅仅是因为,可以使用 Java 的 Applet 来开发 Web 应用,作为浏览器组
件。但开发者们很快就发现这个新兴的语言还能做更多的事情。与之前的所有语言不同,Java 让模块化
构建复杂的系统成为可能(当时的软件行业虽然在业务上突飞猛进,但当时开发用的是传统的面向过程
开发思想,软件的开发效率一直踟蹰不前。伴随着业务复杂性的不断加深,开发也变得越发困难。其实,
当时也是 OOP 思想飞速发展的时期,她在 80 年代末被提出,成熟于 90 年代,现今大多数编程语言都
已经是面向对象的)。
同年 12 月,Sun 公司发布了当时还名不见经传但后来人尽皆知的 JavaBean 1.00-A 规范。早期的
JavaBean 规范针对于 Java,她定义了软件组件模型。这个规范规定了一整套编码策略,使简单的 Java
对象不仅可以被重用,而且还可以轻松地构建更为复杂的应用。尽管 JavaBean 最初是为重用应用组件
而设计的,但当时他们却是主要用作构建窗体控件,毕竟在 PC 时代那才是主流。但相比于当时正如日
中天的 Delphi、VB 和 C++,它看起来还是太简易了,以至于无法胜任任何"实际的"工作需要。
复杂的应用通常需要事务、安全、分布式等服务的支持,但 JavaBean 并未直接提供。所以到了 1998
年 3 月,Sun 公司发布了 EJB 1.0 规范,该规范把 Java 组件的设计理念延伸到了服务器端,并提供了
许多必须的企业级服务,但他也不再像早期的 JavaBean 那么简单了。实际上,除了名字叫 EJB Bean
以外,其他的和 JavaBean 关系不大了。
尽管现实中有很多系统是基于 EJB 构建的,但 EJB 从来没有实现它最初的设想:简化开发。EJB 的
声明式编程模型的确简化了很多基础架构层面的开发,例如事务和安全;但另一方面 EJB 在部署描述符
和配套代码实现等方面变得异常复杂。随着时间的推移,很多开发者对 EJB 已经不再抱有幻想,开始寻
求更简洁的方法。
现在 Java 组件开发理念重新回归正轨。新的编程技术 AOP 和 DI 的不断出现,他们为 JavaBean 提
供了之前 EJB 才能拥有的强大功能。这些技术为 POJO 提供了类似 EJB 的声明式编程模型,而没有引入
任何 EJB 的复杂性。当简单的 JavaBean 足以胜任时,人们便不愿编写笨重的 EJB 组件了。
客观地讲,EJB 的发展甚至促进了基于 POJO 的编程模型。引入新的理念,最新的 EJB 规范相比之
前的规范有了前所未有的简化,但对很多开发者而言,这一切的一切都来得太迟了。到了 EJB 3 规范发
布时,其他基于 POJO 的开发架构已经成为事实的标准了,而 Spring 框架也就是在这样的大环境下出
现的。
Spring 的设计初衷
Spring 是为解决企业级应用开发的复杂性而设计,她可以做很多事。但归根到底支撑 Spring 的仅
仅是少许的基本理念,而所有的这些基本理念都能可以追溯到一个最根本的使命:简化开发。这是一个
郑重的承诺,其实许多框架都声称在某些方面做了简化。而 Spring 则立志于全方面的简化 Java 开发。
对此,她主要采取了 4 个关键策略:
1、基于 POJO 的轻量级和最小侵入性编程;
2、通过依赖注入和面向接口松耦合;
3、基于切面和惯性进行声明式编程;
4、通过切面和模板减少样板式代码;
而他主要是通过:面向 Bean(BOP)、依赖注入(DI)以及面向切面(AOP)这三种方式来达成的。
BOP 编程伊始
Spring 是面向 Bean 的编程(Bean Oriented Programming, BOP),Bean 在 Spring 中才是真正的
主角。Bean 在 Spring 中作用就像 Object 对 OOP 的意义一样,Spring 中没有 Bean 也就没有 Spring
存在的意义。Spring 提供了 IOC 容器通过配置文件或者注解的方式来管理对象之间的依赖关系。
控制反转(其中最常见的实现方式叫做依赖注入(Dependency Injection,DI),还有一种方式叫
“依赖查找”(Dependency Lookup,DL),她在 C++、Java、PHP 以及.NET 中都运用。在最早的
Spring 中是包含有依赖注入方法和依赖查询的,但因为依赖查询使用频率过低,不久就被 Spring 移除
了,所以在 Spring 中控制反转也被直接称作依赖注入),她的基本概念是:不创建对象,但是描述创建
它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容
器 (在 Spring 框架中是 IOC 容器)负责将这些联系在一起。
在典型的 IOC 场景中,容器创建了所有对象,并设置必要的属性将它们连接在一起,决定什么时间
调用方法。
依赖注入的基本概念
Spring 设计的核心 org.springframework.beans 包(架构核心是 org.springframework.core
包),它的设计目标是与 JavaBean 组件一起使用。这个包通常不是由用户直接使用,而是由服务器将
其用作其他多数功能的底层中介。下一个最高级抽象是 BeanFactory 接口,它是工厂设计模式的实现,
允许通过名称创建和检索对象。BeanFactory 也可以管理对象之间的关系。
BeanFactory 最底层支持两个对象模型。
1,单例:提供了具有特定名称的全局共享实例对象,可以在查询时对其进行检索。Singleton 是默
认的也是最常用的对象模型。
2,原型:确保每次检索都会创建单独的实例对象。在每个用户都需要自己的对象时,采用原型模式。
Bean 工厂的概念是 Spring 作为 IOC 容器的基础。
IOC 则将处理事情的责任从应用程序代码转移到
框架。
AOP 编程理念
面向切面编程,即 AOP,是一种编程思想,它允许程序员对横切关注点或横切典型的职责分界线的
行为(例如日志和事务管理)进行模块化。AOP 的核心构造是方面(切面),它将那些影响多个类的行
为封装到可重用的模块中。
AOP 和 IOC 是补充性的技术,它们都运用模块化方式解决企业应用程序开发中的复杂问题。在典
型的面向对象开发方式中,可能要将日志记录语句放在所有方法和 Java 类中才能实现日志功能。在 AOP
方式中,可以反过来将日志服务模块化,并以声明的方式将它们应用到需要日志的组件上。当然,优势
就是 Java 类不需要知道日志服务的存在,也不需要考虑相关的代码。所以,用 Spring AOP 编写的应
用程序代码是松散耦合的。
AOP 的功能完全集成到了 Spring 事务管理、日志和其他各种特性的上下文中。
AOP 编程的常用场景有:Authentication(权限认证)、Auto Caching(自动缓存处理)、Error Handling
(统一错误处理)、Debugging(调试信息输出)、Logging(日志记录)、Transactions(事务处理)等
Spring5 系统架构
Spring 总共大约有 20 个模块,由 1300 多个不同的文件构成。而这些组件被分别整合在核心容器(Core
Container)、AOP(Aspect Oriented Programming)和设备支持(Instrmentation)、数据访问
及集成(Data Access/Integeration)、Web、报文发送(Messaging)、Test,6 个模块集合中。以
下是 Spring 5 的模块结构图:
组成 Spring 框架的每个模块集合或者模块都可以单独存在,也可以一个或多个模块联合实现。每个模
块的组成和功能如下:
核心容器
由spring-beans、spring-core、spring-context和spring-expression(Spring Expression Language,SpEL) 4 个模块组成。
spring-core 和 spring-beans 模块是 Spring 框架的核心模块,包含了控制反转(Inversion of
Control, IOC)和依赖注入(Dependency Injection, DI)。BeanFactory 接口是 Spring 框架中的核
心接口,它是工厂模式的具体实现。BeanFactory 使用控制反转对应用程序的配置和依赖性规范与实际
的应用程序代码进行了分离。但 BeanFactory 容器实例化后并不会自动实例化 Bean,只有当 Bean 被
使用时 BeanFactory 容器才会对该 Bean 进行实例化与依赖关系的装配。
spring-context 模块构架于核心模块之上,他扩展了 BeanFactory,为她添加了 Bean 生命周期控
制、框架事件体系以及资源加载透明化等功能。此外该模块还提供了许多企业级支持,如邮件访问、远
程访问、任务调度等,ApplicationContext 是该模块的核心接口,她的超类是 BeanFactory。与
BeanFactory 不同,ApplicationContext 容器实例化后会自动对所有的单实例 Bean 进行实例化与依
赖关系的装配,使之处于待用状态。
spring-context-support 模块是对 Spring IOC 容器的扩展支持,以及 IOC 子容器。
spring-context-indexer 模块是 Spring 的类管理组件和 Classpath 扫描。
spring-expression 模块是统一表达式语言(EL)的扩展模块,可以查询、管理运行中的对象,同
时也方便的可以调用对象方法、操作数组、集合等。它的语法类似于传统 EL,但提供了额外的功能,最
出色的要数函数调用和简单字符串的模板函数。这种语言的特性是基于 Spring 产品的需求而设计,他
可以非常方便地同 Spring IOC 进行交互。
AOP 和设备支持
由 spring-aop、spring-aspects 和 spring-instrument 3 个模块组成。
spring-aop 是 Spring 的另一个核心模块,是 AOP 主要的实现模块。作为继 OOP 后,对程序员影
响最大的编程思想之一,AOP 极大地开拓了人们对于编程的思路。在 Spring 中,他是以 JVM 的动态
代理技术为基础,然后设计出了一系列的 AOP 横切实现,比如前置通知、返回通知、异常通知等,同
时,Pointcut 接口来匹配切入点,可以使用现有的切入点来设计横切面,也可以扩展相关方法根据需求
进行切入。
spring-aspects 模块集成自 AspectJ 框架,主要是为 Spring AOP 提供多种 AOP 实现方法。
spring-instrument 模块是基于 JAVA SE 中的"java.lang.instrument"进行设计的,应该算是 AOP
的一个支援模块,主要作用是在 JVM 启用时,生成一个代理类,程序员通过代理类在运行时修改类的
字节,从而改变一个类的功能,实现 AOP 的功能。在分类里,我把他分在了 AOP 模块下,在 Spring 官
方文档里对这个地方也有点含糊不清,这里是纯个人观点。
数据访问与集成
由 spring-jdbc、spring-tx、spring-orm、spring-jms 和 spring-oxm 5 个模块组成。
spring-jdbc 模块是 Spring 提供的 JDBC 抽象框架的主要实现模块,用于简化 Spring JDBC 操作 。
主要是提供 JDBC 模板方式、关系数据库对象化方式、SimpleJdbc 方式、事务管理来简化 JDBC 编程,
主要实现类是 JdbcTemplate、SimpleJdbcTemplate 以及 NamedParameterJdbcTemplate。
spring-tx 模块是 Spring JDBC 事务控制实现模块。使用 Spring 框架,它对事务做了很好的封装,
通过它的 AOP 配置,可以灵活的配置在任何一层;但是在很多的需求和应用,直接使用 JDBC 事务控
制还是有其优势的。其实,事务是以业务逻辑为基础的;一个完整的业务应该对应业务层里的一个方法;
如果业务操作失败,则整个事务回滚;所以,事务控制是绝对应该放在业务层的;但是,持久层的设计
则应该遵循一个很重要的原则:保证操作的原子性,即持久层里的每个方法都应该是不可以分割的。所
以,在使用 Spring JDBC 事务控制时,应该注意其特殊性。
spring-orm 模块是 ORM 框架支持模块,主要集成 Hibernate, Java Persistence API (JPA) 和
Java Data Objects (JDO) 用于资源管理、数据访问对象(DAO)的实现和事务策略。
spring-oxm 模块主要提供一个抽象层以支撑 OXM(OXM 是 Object-to-XML-Mapping 的缩写,
它是一个 O/M-mapper,将 java 对象映射成 XML 数据,或者将 XML 数据映射成 java 对象),例如:
JAXB, Castor, XMLBeans, JiBX 和 XStream 等。
spring-jms 模块(Java Messaging Service)能够发送和接收信息,自 Spring Framework 4.1 以
后,他还提供了对 spring-messaging 模块的支撑。
Web 组件
由 spring-web、spring-webmvc、spring-websocket 和 spring-webflux 4 个模块组成。
spring-web 模块为 Spring 提供了最基础 Web 支持,主要建立于核心容器之上,通过 Servlet 或
者 Listeners 来初始化 IOC 容器,也包含一些与 Web 相关的支持。
spring-webmvc 模块众所周知是一个的 Web-Servlet 模块,实现了 Spring MVC
(model-view-Controller)的 Web 应用。
spring-websocket 模块主要是与 Web 前端的全双工通讯的协议。
spring-webflux 是一个新的非堵塞函数式 Reactive Web 框架,可以用来建立异步的,非阻塞,
事件驱动的服务,并且扩展性非常好。
通信报文
即 spring-messaging 模块,是从 Spring4 开始新加入的一个模块,主要职责是为 Spring 框架集
成一些基础的报文传送应用。
集成测试
即 spring-test 模块,主要为测试提供支持的,毕竟在不需要发布(程序)到你的应用服务器或者连接
到其他企业设施的情况下能够执行一些集成测试或者其他测试对于任何企业都是非常重要的。
集成兼容
即 spring-framework-bom 模块,Bill of Materials.解决 Spring 的不同模块依赖版本不同问题。
各模块之间的依赖关系
Spring 官网对 Spring5 各模块之间的关系也做了详细说明:
接下来的课程中,我们将深入了解 Spring 的核心模块功能。基本学习顺序为:从 spring-core 入手,
其次是 spring-beans 和 spring-aop,随后是 spring-context,再其次是 spring-tx 和 spring-orm,
最后是 spring-web 和其他部分。
Spring 版本命名规则
常见软件的版本号命名 ,自己百度一下
Spring 源码下载及构建技巧
Spring5 源码下载注意事项
首先你的 JDK 需要升级到 1.8 以上。Spring3.0 开始,Spring 源码采用 github 托管,不再提供官网下载
链接。这里不做过多赘述,大家可自行去 github 网站下载,我们使用的版本下载链接为:
https://github.com/spring-projects/spring-framework/archive/v5.0.2.RELEASE.zip,下载完成后,
解压源码包会看到以下文件目录:
基于 Gradle 的源码构建技巧
由于 Spirng5 以后都是采用 Gradle 来编译,所以构建源码前需要先安装 Gradle 环境。Gradle 下载地
址:https://gradle.org/releases,我使用的是 Spring5 官方推荐的版本 Gradle4.0,下载链接为:
https://gradle.org/next-steps/?version=4.0&format=bin , 下 载 完 成 后 按 以 下 步 骤 操 作 , 以
Windows 操作系统为例:
第一步:配置环境变量
第二步:添加环境变量:Path:%GRADLE_HOME%in
第三步:检测环境,输入 gradle -v 命令,得到以下结果:
第四步:编译源码,cmd 切到 spring-framework-5.0.2.RELEASE 目录,运行 gradlew.bat
第五步:转换为 eclipse 项目,执行 import-into-eclipse.bat 命令,构建前,请确保网络状态良好,按
任意键继续。
第六步:等待构建成功(若中途出现错误,大部分情况是由于网络中断造成的,重试之后一般都能解决
问题),构建成功后,会出现如下界面:
到这一步为止,还在使用 Eclipse 的小伙伴已经可以将项目导入到 Eclipse 中了。而我们推荐使用的 IDEA
也比较智能,可以直接兼容 Eclipse 项目。接下来看下面的步骤:
第七步:导入 IDEA。打开 IntelliJ IDEA,点击 Import Project,弹出如下界面,选择
spring-framework-5.0.2.RELEASE 文件夹:
第八步:等待构建完成,在网络良好的情况下大约需要 10 分钟便可自动构建完成,你会看到如下界面:
第九步:在 IDEA 中,如果 Project 下的子项目文件夹变成粗体字之后,说明已经构建成功。还有一种
验证方式是:找到 ApplicationContext 类,按 Ctrl + Shift + Alt + U,出现类图界面说明构建成功
如果我已经将构建好的“spring-framework-5.0.2.RELEASE-中文注释版”,提交到了 Git 上,下载后导入到 IDEA 中
开箱即用,无需重复构建。
Gradle 构建过程中的坑
如果项目环境一直无法构建,项目文件夹没有变粗体字,类图无法自动生成。那么你一定是踩到了这样一个坑。
第一步:首先打开 View->Tool Windows -> Gradle
然后,点击右侧 Gradle 视图中的 Refresh,会出现如下的错误:
第二步:看错误,显然跟 Gradle 没有任何关系,解决办法:
1.关闭 IDEA,打开任务管理器,结束跟 java 有关的所有进程。
2.找到 JAVA_HOME -> jre -> lib 目录,将 tools.jar 重命名 tools.jar.bak。
3.重启 IDEA,再次点击 refresh,等待构建完成。