Spring
IOC 控制反转
概念:把对 Bean 的控制权交给 Spring 容器。
循环依赖
Spring Bean 的循环依赖是通过三级缓存解决的。
假设有A、B、C三个bean,A引用B,B引用C,C引用A,spring就根据依赖关系把它们全都放到三级缓存里面,当创建C想把A注入到C里面的时候,发现A还在创建当中,一级缓存里面没有A,然后就从三级缓存里通过A的工厂获取A实例,把A实例提到二级缓存中,直接就把这个还没初始化的A注入到C当中,这样C就完成初始化了,然后把C提到一级缓存中,然后继续把C注入给B,把B注入回给A,这样就完成了ABC的初始化,这就是spring创建循环依赖的Bean的过程。
| 级别 | 各级缓存的区别 |
|---|---|
| 一级 | SingletonObjects,存储单例对象,Bean 已经实例化、初始化 |
| 二级 | EarlySingletonObjects,存储 singletonObject,这个 Bean 实例化了,还没有初始化 |
| 三级 | SingletonFactories,存储 singletonFactory |
Bean 的作用域
| 作用域 | 描述 |
|---|---|
| singleton | 以单例的形式存在,只有一个bean |
| prototype | 多实例,每次调用getBean()时会返回一个新的实例 |
| request | 每次 HTTP 请求都创建一个新的bean |
| session | 一个session共用一个bean。不同session使用不同的bean |
Bean 的生命周期
- 创建实例
- 属性赋值
- 初始化
- bean 正常使用
- 容器关闭,bean 销毁
单实例和多实例的不同
- 单实例下 bean 的生命周期:
容器启动——>初始化方法——>(容器关闭)销毁方法
- 多实例下 bean 的生命周期:
容器启动——>调用 bean ——>初始化方法——>容器关闭(销毁方法不执行)
Bean 属性的注入方式
- 构造方法注入
- setter 方法注入
部分设计模式
创建Bean的时候使用了单例模式、工厂设计模式
AOP 用到代理模式、适配器模式(功能增强和通知)
Spring 事务管理也是用到了代理模式,因为本质也是 AOP
Spring 事务
事务是数据库层面的,Spring 只是基于数据库事务进行扩展。Spring 中有两种事务实现方式:申明式 与 编程式,注解 @Transaction 就属于申明式。
Spring 事务隔离级别
| 隔离级别 | 说明 |
|---|---|
| read uncommitted | 未提交读 |
| read committed | 已提交读、不可重复读 |
| repeatable read | 可重复读 |
| serializable | 可串行化 |
Mysql 默认的隔离级别是 可重复读
Oracle 和 SqlServer 都是已提交读
数据库配置的隔离级别是已提交读而 Spring 配置的隔离级别是可重复读,这个时候以 Spring 配置的为准,如果 Spring 设置的隔离级别数据库不支持那效果就取决于数据库本身。
@Transaction
Spring 会基于这个类生成一个代理对象,会将这个代理对象作为一个 bean 使用这个代理对象的方法。
提示
如果方法上存在 @transaction 注解,那么代理逻辑会先把事务的自动提交设置为false,然后再去执行原本业务逻辑方法,如果没有出现异常那么代理逻辑中就会将事务进行提交,如果执行业务中出现异常则会进行事务回滚。
Spring 默认会对 RuntimeException 和 Error 进行回滚,可以使用 rollback 属性配置。
事务传播机制
在 Spring 事务管理当中,对调用链中的子方法的事务处理策略叫做事务传播行为,也叫事务传播机制。
事务传播机制基本上就分为这3类:
- 优先使用当前事务
- 不适用当前事务,开启新的事务
- 不使用任何事务
| 传播方式 | 说明 |
|---|---|
| Required | 如果当前没有事务,则自己新建一个事务,如果当前存在事务则加入这个事务(默认) |
| Supports | 当前存在事务则加入当前事务,如果当前没有事务,就以非事务方式执行 |
| Mandatory | 当前存在事务则加入当前事务,如果当前没有事务就以非事务方法执行 |
| never | 不适用事务,如果当前事务存在,则抛出异常 |
| nested | 如果当前事务存在,则在嵌套事务中执行,否则Required的操作一样(开启一个事务) |
| Requires_new | 创建一个新事务,如果当前存在事务,则挂起该事务 |
| Not_supported | 以非事务方式执行,如果当前存在事务,则挂起当前事务 |
Spring 事务什么时候会失效?
Spring 事务原理就是AOP进行切面增强,多数情况下原因是这个切面不生效了
- 没有被 Spring 管理
- 方法不是 public,事务 @Transaction 只能用于 public 方法上
- 类内部自身调用,类里面使用
this调用本类的方法(this通常省略),此时这个this对象不是代理类,而是原始类所以不生效 (解决: 将当前调用方法变成代理类) - 异常捕获或者是抛出异常没有被定义,默认为 RuntimeException
- 数据库不支持
