【spring循环依赖】

文章目录

  • Bean的生命周期
  • 三级缓存
  • 总结

Bean的生命周期

被Spring管理的对象叫做Bean。Bean的生成步骤如下:

  1. Spring扫描class得到BeanDefinition
  2. 根据得到的BeanDefinition去生成bean
  3. 首先根据class推断构造方法
  4. 根据推断出来的构造方法,反射,得到一个对象(暂时叫做原始对象)
  5. 填充原始对象中的属性(依赖注入)
  6. 如果原始对象中的某个方法被AOP了,那么则需要根据原始对象生成一个代理对象
  7. 把最终生成的代理对象放入单例池(源码中叫做singletonObjects)中,下次getBean时就直接从单例池拿即可。

三级缓存

三级缓存是通用的叫法。 一级缓存为:singletonObjects 二级缓存为:earlySingletonObjects
三级缓存为**:singletonFactories**
先稍微解释一下这三个缓存的作用,后面详细分析:
singletonObjects中缓存的是已经经历了完整生命周期的bean对象。
earlySingletonObjects比singletonObjects多了一个early,表示缓存的是早期的bean对象。
早期是什么意思?表示Bean的生命周期还没走完就把这个Bean放入了earlySingletonObjects。

singletonFactories中缓存的是ObjectFactory,表示对象工厂,表示用来创建早期bean对象的
工厂。

  1. singletonObjects:缓存经过了完整生命周期的bean
  2. earlySingletonObjects:缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,
    就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果
    要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入
    earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是
    没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整
    生命周期的bean。
  3. singletonFactories:缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean
    的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达
    式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出
    现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后
    直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖
    (当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行
    Lambda表达式得到一个对象,并把得到的对象放入二级缓存(
    (如果当前Bean需要AOP,那么
    执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象))。
  4. 其实还要一个缓存,就是earlyProxyReferences,它用来记录某个原始对象是否进行过AOP
    了。

反向分析一下singletonFactories
为什么需要singletonFactories?假设没有singletonFactories,只有earlySingletonObjects,
earlySingletonObjects是二级缓存,它内部存储的是为经过完整生命周期的bean对象,Spring原有
的流程是出现了循环依赖的情况下:

  1. 先从singletonFactories中拿到lambda表达式,这里肯定是能拿到的,因为每个bean实例化之
    后,依赖注入之前,就会生成一个lambda表示放入singletonFactories中
  2. 执行lambda表达式,得到结果,将结果放入earlySingletonObjects中
    那如果没有singletonFactories,该如何把原始对象或AOP之后的代理对象放入
    earlySingletonObjects中呢?何时放入呢?
    首先,将原始对象或AOP之后的代理对象放入earlySingletonObjects中的有两种:
  3. 实例化之后,依赖注入之前:如果是这样,那么对于每个bean而言,都是在依赖注入之前会去
    进行AOP,这是不符合bean生命周期步骤的设计的。
  4. 真正发现某个bean出现了循环依赖时:按现在Spring源码的流程来说,就是
    getSingleton(String beanName, boolean allowEarlyReference)中,是在这个方法中判断出
    来了当前获取的这个bean在创建中,就表示获取的这个bean出现了循环依赖,那在这个方法中
    该如何拿到原始对象呢?更加重要的是,该如何拿到AOP之后的代理对象呢?难道在这个方法中
    去循环调用BeanPostProcessor的初始化后的方法吗?不是做不到,不太合适,代码太丑。**最
    关键的是在这个方法中该如何拿到原始对象呢?**还是得需要一个Map,预习把这个Bean实例
    化后的对象存在这个Map中,那这样的话还不如直接用第一种方案,但是第一种又直接打破了
    Bean生命周期的设计。

总结

所以,我们可以发现,现在Spring所用的singletonFactories,为了调和不同的情况,在
singletonFactories中存的是lambda表达式,这样的话,只有在出现了循环依赖的情况,才会执行
lambda表达式,才会进行AOP,也就说只有在出现了循环依赖的情况下才会打破Bean生命周期的设
计,如果一个Bean没有出现循环依赖,那么它还是遵守了Bean的生命周期的设计的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值