spring的循环依赖与三级缓存

1. 三级缓存的作用

  • 一级缓存,存放完整的spring Bean
  • 二级缓存,存放提前暴露的bean,作用是为了处理循环依赖的对象创建问题,里面存放的是半成品对象或半成品对象的代理对象
  • 三级缓存,存放的是bean简单工厂,主要是生产bean或者bean的代理对象

2. 为什么要引入三级缓存

  • 第三级缓存并非缺它不可,因为可以提前创建代理对象
  • 但是提前创建代理对象会破坏spring的设计原则(尽可能地保证普通对象创建完成之后,再生成aop代理,即尽可能延迟代理对象的生成)
  • 所以spring用来三级缓存,既维持了设计原则,又处理了循环依赖;牺牲了一点内存空间是可以接受的

3. 循环依赖的处理过程(无AOP过程)

a,b循环依赖

  • a实例化之后(半成品),将a的objectFactory对象放入三级缓存
  • 初始化a(给a填充属性),又去创建b
  • b实例化后(半成品),将b的objectFactory对象放入三级缓存
  • 初始化b(给b填充属性),从容器中获取a
    • 从三级缓存中查到a的objectFactory对象,调用这个工厂的getObject()返回之前创建的半成品a实例,将半成品a放入二级缓存,并将三级缓存中的a的bean工厂移除,最终返回半成品a,开始回溯
  • b的初始化完成,b成为正品,从三级缓存中将b的objectFactory对象移除,将实例b放入一级缓存。继续回溯
  • 继续给a初始化,完成属性注入。a成为正品,将a放入一级缓存并从二级缓存中移除。
  • a,b均创建成功

4. 循环依赖的处理过程(加入AOP过程)

  • a实例化之后(半成品),将a的objectFactory对象放入三级缓存
  • 初始化a(给a填充属性),又去创建b
  • b实例化后(半成品),将a的objectFactory对象放入三级缓存
  • 初始化b(给b填充属性),从容器中获取a
    • 从三级缓存查到a的ObjectFactory对象。调用工厂的getObject()方法会根据需求而返回实例对象或者实例对象的代理对象,这里因为需要加入AOP所以调用getObject方法会返回半成品a的代理对象,并将代理对象放入二级缓存,将三级缓存中的半成品对象a的objectFactory对象移除,开始回溯(注意,这里就一定需要三级缓存了,如果是加入了AOP过程,a的objcetFactory对象每次调用getObject方法都会生成一个新的代理对象,这样就不满足单例的情况.所以当三级缓存中a的工厂对象第一次生产出a的代理对象,将这个代理对象放到二级缓存,然后删除三级缓存中a的工厂对象)
  • 给b填充完属性a后,完成初始化过程,然后创建成品b的代理对象
  • 将成品b的代理对象直接放入一级缓存,将b的工厂对象从三级缓存中移除
  • a进行属性注入,然后创建过程回溯到initializeBean(),由于a的代理对象已经创建(在二级缓存中),所以无需再重新创建代理对象,只需要将a的代理对象从二级缓存提到一级缓存即可。
  • 完成a,b成品代理对象的建立。

5. 总结

  • 一级缓存也可以解决循环依赖,但是这样半成品对象,成品对象,半成品对象的代理对象,成品对象的代理对象四种对象都放在一个缓存里,有点乱,设计过于耦合(用的时候你还需要检验你这个对象是否是成品
  • 二级缓存也可以解决循环依赖,比如一级缓存放成品对象或成品对象的代理对象,二级缓存放半成品对象或半成品的代理对象
    • 但这种情况就是,不管有没有循环依赖,当我们最终需要的是代理对象都需要提前创建好代理对象将半成品对象的代理对象放入二级缓存。出现循环依赖时,其他对象直接就可以取到代理对象并注入。
    • 但是Spring并没有这么做,Spring的设计原则是尽量在最后创建代理对象。如果有循环依赖且需要AOP的情况下,才会提前创建代理对象。如果没有循环依赖但需要AOP的情况下,它不会提前创建代理对象,而是在对象初始化之后再创建代理对象。
  • 三级缓存肯定也可以解决循环依赖,而且还符合Spring的设计原则。(对象需要AOP功能也不会提前创建好代理对象,只有当出现循环依赖被其他对象注入时,才会提前实时生成代理对象)
    • 三级缓存:放对象的objectFactory对象
    • 二级缓存:如果需要AOP且被循环依赖,则放半成品对象的代理对象。其他情况放半成品对象
    • 一级缓存:需要AOP则放成品对象的代理对象,不需要AOP的放成品对象

6. 补充

  • 一般情况下,当单例bean需要AOP功能时,在这个单例bean完成了初始化后,由AnnotationAwareAspectJAutoProxyCreator这个bean后置处理器调用postProcessAfterInitialization方法来实现对单例bean完成AOP代理的。
  • 如果这个单例bean需要AOP功能而且又被循环依赖时,则这个代理对象创建时机会提前,当首次调用这个单例bean的objectFactory对象的getObject方法时,内部会调用AnnotationAwareAspectJAutoProxyCreator的getEarlyBeanReference方法,生成这个半成品单例bean的代理对象。然后在之后这个单例bean完成初始化后,在AnnotationAwareAspectJAutoProxyCreator这个bean后置处理器调用postProcessAfterInitialization方法时,它会先检查提前创建了代理对象,如果提前创建了,那么它就不会再重复创建代理对象。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值