1、简介
Spring 是 Java EE 编程领域的一个轻量级开源框架,同时也是针对 Bean 的生命周期进行管理的轻量级容器(lightweight container)框架。在整个框架中,各类型的功能被抽象成一个个的 Bean 并通过 Bean Factory 实现了对 Bean 生命周期的管理。
Spring 框架 是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在 核心容器 之上,核心容器定义了创建、配置 和 管理 Bean 的方式。组成 Spring 框架 的每个 模块(或组件)都可以单独存在,或者与其它一个(或多个)模块 联合实现。
补充:
Spring 的七大组成:
-
Spring Core(核心模块)
提供 Spring 框架的基本功能,主要组件是 BeanFactory(工厂模式的实现),BeanFactory 使用 控制反转(IOC)模式 将应用程序的 配置和依赖性规范 与实际的应用程序代码分开。
-
Spring AOP(Spring Aspect Oriented Programing)
通过配置管理特性,将 面向切面(AOP)的编程功能 直接集成到 Spring 中,并为 Bean 提供了事务管理服务。
-
Spring ORM(Object Relational Mapping)
负责框架中的 对象关系映射,提供相关 ORM 接入框架 的关系对象管理工具(JDO、Hibernate、iBatis)。
-
Spring DAO(Data Access Objects)
提供 管理 异常处理 和 不同数据库供应商抛出的错误消息 的异常层次结构,简化了错误处理,降低了异常代码量(如:打开和关闭连接)。
-
Spring Context
Spring Context 是一个 配置文件,向 Spring 框架 提供上下文信息。Spring Context 还包括 企业服务,如:JNDI、EJB、电子邮件、国际化、校验和调度功能。
-
Spring Web
为基于 Web 的应用程序提供 上下文,简化了 处理多部分请求 和 将请求参数绑定到 域对象 的工作。
-
Spring Web MVC(Spring Web Model View Controller)
Spring Web MVC 是一个 全功能的构建 Web 应用程序的 MVC 实现,Model 由 JavaBean 构成,存放于 Map;View 是一个接口,负责显示 Model;Controller 负责对 Model 和 View 的逻辑处理。
2、Spring 的特征:
-
轻量
完整的 Spring 可以在一个 大小 只有 1MB 多的 JAR 文件里发布,并且 Spring 所需的处理开销也是微不足道的。
-
非入侵式
Spring 应用中的 对象不依赖于 Spring 的特定类。
-
控制反转(IOC,Inversion of Control)
控制反转 是一种 面向对象 编程的设计思想,主要内容是:设计的类 将交由 容器 去控制,而不是在 类的内部 去控制,类与类之间的关系 将交由 容器 处理,一个类 在需要调用 另一个类 时,只要调用 另一个类 在容器中注册的名字 就可以得到这个类的实例。
Spring 的 IOC 底层设计模式 采用了 工厂模式,所有的 Bean 都需要注册到 Bean 工厂中,将其初始化 和 生命周期的监控 交由 工厂实现管理;程序员 只需要按照规定的格式进行 Bean 开发,然后利用 XML 文件(SpringBoot 可通过注解) 进行 Bean 的 定义和参数配置,其它的动态生成和监控 就不需要调用者完成,而是统一交给了 平台 进行管理。
补充:
控制反转的实现方式:
-
依赖注入(DI,Dependency Injection)
一个 对象 依赖的其它对象 会通过被动的方式 传递进来,而不是这个 对象 自己创建或者查找 依赖对象。
实现依赖注入的关键是 IoC 容器,它的本质就是一个工厂。
依赖注入的三种实现方式:
-
构造方法注入
被注入对象 可以在 它的构造方法 中声明 依赖对象 的参数列表,让外部知道它需要哪些 依赖对象。然后,IoC Service Provider 会检查 被注入对象的构造方法,取得它所需要的 依赖对象列表,进而为其注入相应的对象。
构造方法注入 比较直观,对象被构造完成后,即进入 就绪状态(可以立即使用)。
-
setter 方法注入
被注入对象 可以为其 依赖对象所对应的属性 添加 setter 方法(setter 方法 可以更改相应的对象属性),IoC Service Provider 即可通过 setter 方法,将 相应的依赖对象 设置到被注入对象中。
setter 方法注入 相较于 构造方法注入 条件更宽松些,可以在对象构造完成之后再注入。
-
接口注入(不推荐)
被注入对象 如果想要 IoC Service Provider 为其注入依赖对象,就必须 实现某个接口,该接口将提供一个方法,用来为其注入依赖对象。
接口注入 相较于 前两种 依赖注入方式 步骤更为死板和繁琐。
-
-
面向切面编程(AOP,Aspect Oriented Programing)
面向切面编程 既是 一种编程思想,是对 面对对象编程(OOP)思想的补充,在 OOP 的基础进一步提高编程效率,也是 一种通过 预编译方式 和 运行期间动态代理 实现程序功能 统一维护 的技术。
AOP 是 函数式编程 的一种衍生类型,通过 AOP,可以对 业务逻辑 的各个部分进行隔离,从而使得业务逻辑各部分之间的 耦合度 降低,在提高 程序可重用性 的同时 提高了 开发效率。
例如:将 日志记录、性能统计、安全控制、事务处理、异常处理等代码 从业务逻辑代码中 独立出来,使得 在改动这些功能的代码时 不会对 业务逻辑代码 产生任何影响。
补充:AOP 术语
- Aspect(切面):Aspect 声明 类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice
- Joint point(连接点):表示在程序中明确定义的点,主要包括 方法调用、对类成员的访问 和 异常处理程序块的执行 等,它自身还可以嵌套其它 Joint point
- Pointcut(切点):表示一组 Joint point,这些 Joint point 或是 通过 逻辑关系 组合起来,或是通 通配、正则表达式 等方式集中起来,它定义了相应的 Advice 将要发生的地方
- Advice(通知):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 或 around 来区别是在每个 Joint point 之前、之后 或 代替执行的代码。
- Target(目标对象):织入 Advice 的目标对象
- Weaving(织入):将 Aspect 和 其它对象连接起来,并创建 Adviced object 的过程
- Introduction(引入):引入新的类和其方法,增强现有 Bean 的功能
-
容器
Spring 包含并管理 应用对象的配置和生命周期,在这个意义上它是一种容器。
-
框架
Spring 可以将 简单的组件 配置、组成成为复杂的应用。
-
MVC
客户端的请求,经由 Model(模型)、View(视图)、控制器(Controller)分层处理并给予相应的反馈。
3、Bean 的生命周期
Bean 的生命周期 包括:实例化 --> 初始化 --> 调用 --> 销毁 。
Bean 的整个生命周期都是 Spring 容器自动管理的,其中只有两个环节我们可以进行干预:
- 自定义初始化方法(@PostConstruct 进行标注)
- 自定义销毁方法(@PreDestroy 进行标注)
补充:Bean 的作用域
默认情况下,Bean 在 Spring 容器中是单例的,我们可以通过 @Scope 修改 Bean 的作用域。
@Scope 的取值及含义:
| 取值 | 含义 |
|---|---|
| singleton(单例) | 在 Spring 容器中仅存在一个实例 |
| prototype(原型) | 每次调用 getBean() 时,都会返回一个新的实例 |
| request | 每次 HTTP 请求都会创建一个新的实例 |
| session | 同个 HTTP Session 共享一个实例 |
| globalSession | 同个全局 Session 共享一个实例 |
4、Spring Bean 的管理
Spring 通过 IoC 容器来对 Bean 进行管理,我们可以通过 XML 配置 或者 注解配置,来指导 IoC 容器对 Bean 的管理。因为 注解配置 相较于 XML 配置 更为便捷,因而我们大多数时候都是通过 注解 进行配置。
管理 Bean 的相关注解:
| 注解 | 说明 |
|---|---|
| @ComponentScan | 扫描 xx包中 Bean,也可以排除指定的 Bean |
| @Component、@Repository、@Service、@Controller | 声明该类是一个 Bean |
| @Autowired、@Qualifier | 向 IoC 容器中注入 Bean |
| @Scope | 声明 Bean 的作用域 |
| @PostConstruct、@PreDestroy | 声明 Bean 生命周期中的自定义方法 |
补充:BeanFactory
BeanFactory 是 类的通用工厂,它可以 创建并管理 各种类的对象,这些对象 Spring 称之为 Bean。
BeanFactory 是 Spring 容器的顶层接口,Spring 为其提供了多种实现,最常用的是 XMLBeanDefinitionReader、DefaultListableBeanFactory。
BeanFactory 最主要的方法是 getBean(String beanName):从容器中返回特定名称的 Bean。
扩展:@Autowired 和 @Resource 的区别
-
@Autowired 是 Spring 提供的注解;@Resource 是 JDK 提供的注解
-
@Autowired 只能按类型注入;@Resource 默认名称注入,同时也支持按类型注入
-
@Autowired 默认情况下 要求依赖对象必须存在(如果允许为 null 值,可以设置 required 属性为 false),如果想 使用名称进行注入 则需要配合 @Qualifier 一起使用;
@Resource 的 name 属性指定 Bean 的名称,如果没有指定 name,当 注解 标注在字段上,则默认取字段的名称作为 Bean 名称寻找依赖对象;当 注解 标注在属性的 setter 方法上,则默认取属性名作为 Bean 名称寻找依赖对象;当 按照 默认名称 找不到依赖对象时,则 按类型(type 属性)进行注入。
5、Spring 的循环依赖问题
Spring 三种循环依赖:
- 构造器的循环依赖
- 单例模式下的 setter 循环依赖
- 非单例循环依赖
这三种循环依赖 只有第二种 Spring 可以通过 “三级缓存” 进行处理,其它两种 Spring 都无法处理,第一种 Spring 会直接抛出 BeanCurrentlyInCreationException 异常。
补充:
“三级缓存” 处理:
- singletonObject(一级缓存):存放 完成初始化的单例对象的 Cache
- earlySingletonObject(二级缓存):存放 完成实例化 但未初始化 且提前曝光 的单例对象的 Cache
- singleFactories(三级缓存):存放 进入实例化阶段的单例对象工厂的 Cache
6、Spring 的事务管理
Spring 对事务进行了更高层次的抽象,为事务管理提供了一致的编程模版,使得 用户无论是选择 Hibernate、MyBatis、或是 Spring JDBC,都可以使用统一的编程模型进行事务管理。
Spring 支持的两种事务编程模型:
-
编程式事务
Spring 提供了 Transaction Template 模版,利用该模版我们可以通过编程的方式实现事务管理,而无需关注 资源获取、复用、释放、事务同步及异常处理等操作。
private static TransactionTemplate transactionTemplate;
-
声明式事务
Spring 允许我们通过声明(添加 @Transactional 注解)的方式,在 IoC 配置中指定 事务的边界和事务属性,Spring 会自动在指定的事务边界上应用事务属性。
@Transactional public String service() { ... }
补充:
1、@Transactional 可以标注在 类 或 方法上
- 当它标注在 类 上时,代表这个类所有 公共非静态的方法 都将启动事务功能
- 当它标注在 方法 上时,代表这个方法将启动事务功能
2、@Transactional 的常用属性
- isolation:声明事务的隔离级别
- propagation:声明事务的传播方式
7、Spring 的事务传播方式
当我们调用一个业务方法时,它的内部可能会调用其它的业务方法,以完成一个完整的业务操作。这种业务方法嵌套调用时,如果这两个方法都是要保证事务的,那么就要通过 Spring 的事务传播机制 控制 当前事务 如何传播到 被嵌套调用的业务方法中。
Spring 的 7 种事务传播方式:
| 事务传播方式 | 说明 |
|---|---|
| PROPAGATION_REQUIRED(默认传播方式) | 如果当前不存在事务,则创建一个新事务;如果当前存在事务,则加入该事务 |
| PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,则将当前事务挂起 |
| PROPAGATION_SUPPORTS | 如果当前不存在事务,则以非事务执行;如果当前存在事务,则加入该事务 |
| PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,则将当前事务挂起 |
| PROPAGATION_MANDATORY | 如果当前不存在事务,则抛出异常;如果当前存在事务,则加入该事务 |
| PROPAGATION_NEVER | 以非事务方式执行操作,如果当前存在事务,则抛出异常 |
| PROPAGATION_NESTED | 如果当前不存在事务,则创建一个新事务;如果当前存在事务,则在嵌套事务内执行 |



