Spring
# Sring
# Bean生命周期
# 简单版
- 实例化,调用类的无参构造方法,生成普通对象
- 依赖注入(反射给加了@Autowired和@Resource的属性赋值)
- 初始化前
- 检查Aware的相关接口并设置相关依赖
- 调用BeanPostProcessor的postProcessorBeforeInitialization()
- 是否实现InitializingBean接口,调用afterPropertiesSet()方法
- 是否配置自定义的init-method方法
- 初始化
- 初始化后
- 调用BeanPostProcessor的postProcessAfterInitialization()
- AOP就是在这个阶段
- 使用中
- 销毁
- 是否实现DisposableBean接口,调用destroy()方法
- 是否配置自定义的destroy-method方法
# 循环依赖

# 循环依赖的场景
A创建的过程需要B,于是A将自己放到三级缓存,去实例化B,B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再去三级缓存找A,找到了,把A挪到二级缓存,然后B实例化完成
# 循环依赖的情况
- 属性循环依赖
- 构造器循环依赖----这种情况Spring无法解决循环依赖
# 三级缓存
- 三级缓存
- 一级缓存:SingletonObjects,存放已经实例化好并初始化好的完整对象
- 二级缓存:EarlySingletonObjects,存放需要提前暴露的已经实例化但未初始化好的早期对象
- 三级缓存:SingletonFactories,存放对象工厂(lambda表达式,打破循环依赖的关键,解决AOP依赖原始对象的问题)
- 其实还有一个缓存,就是earlyProxyReferences,它用来记录某个原始对象是否进行过AOP增强,如果进行了增强,那么在循环依赖的时候,需要把earlyProxyReferences中的对象也拿出来放到二级缓存中
# 循环依赖的解决
当A、B两个类发生循环依赖时:

A实例的初始化过程:
- 创建 A 实例,实例化的时候把 A 的对象工厂放入三级缓存,表示 A 开始实例化了,虽然这个对象还不完整,但是先曝光出来让大家知道。

- A 注入属性时,发现依赖 B,此时 B 还没有实例化,所以去实例化 B
- 同样,B 注入属性时发现依赖 A,就从缓存中找 A 对象。依次从一级到三级缓存查询 A。
发现可以从三级缓存中通过对象工厂拿到 A,虽然 A 还不太完善,但是存在,就把 A 放入到二级缓存,同时删除三级缓存中的 A,此时 B 已经实例化并且初始化完成了,把 B 放入到一级缓存。

- 接着 A 继续属性赋值,顺利从一级缓存拿到实例化且初始化好的 B 对象,A 对象初始化完成,删除二级缓存中 A ,同时把 A 放入到一级缓存。
- 最后,一级缓存中保存着实例化和初始化好的 A 、B对象。

# 只用两级缓存能解决循环依赖吗?
- 通常情况可,但是如果涉及AOP,还是需要三级缓存
- 假设只有二级缓存,在二级缓存中放的一个普通Bean对象,Bean初始化过程中,通过BeanPostProcessor去生成代理对象之后,覆盖掉二级缓存中的普通Bean对象,就会导致Bean对象不一致了
# AOP
# 静态代理
- 静态代理模式:自己手动编写代理类,代理类和被代理类实现相同的接口
- 优点:可以做到在代理类中增强被代理类的功能
- 缺点:需要为每一个被代理类都编写一个代理类,工作量比较大
# 动态代理
# 动态代理模式
JDK动态代理和CGLIB动态代理
# JDK动态代理
需要被代理类实现接口,否则无法使用JDK动态代理,反射生成一个代理接口的匿名类
# CGLIB动态代理
asm字节码编辑技术,基于classload装载
# 事务
# 事务类型
- 编程式事务
- 声明式事务
# 事务原理
- 前提是关闭自动提交
- 采用不同的连接器
- 用AOP新建立链接
- ThreadLocal管理当前事务
# 事务隔离级别
- 读未提交Read Uncommitted
- 读已提交Read Committed
- 不可重复读Repeatable Read
- 串行化Serializable
# 事务传播行为

# Spring常用注解

编辑 (opens new window)
上次更新: 2024/06/01, 23:33:02