Spring循环依赖的问题

 
什么是循环依赖?就是两个Bean相互引用,比如用@Autowire 相互注入。
 
那么Spring是如何解决这个问题的呢?在Bean还未完全实例化前(类只实例化了一部分),将bean提前暴露出来,可以被其他Bean引用。
 
源码解析:
 
问题1:什么情况下需要提前暴露?
 
Spring托管的bean是通过getBean()–>doCreateBean()创建的。
 
正常情况下,单例模式,第一次调用getBean单例初始化完成后,直接放入cache了,后面再次调用直接从cache拿,不用走doCreateBean 了。
 
0
 
 
当有循环依赖时候,第二次调用getBean代码earlySingletonExposure就会=true,那么
就会触发行提前暴露bean的逻辑。
 
关键代码:addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
 
AbstractAutowireCapableBeanFactory.doCreateBean();
 
0
 
 
 
问题2: 提前暴露出去的对象是指定类型的Bean的实例本身吗?
不是的,是一个ObjectFactory用于创建该Bean实例 。因为Spring AOP机制,bean在后续实例化过程中可能会被BeanPostProcess处理,生成一个Proxy对象。
 
问题3: 是怎么提前暴露出去的?
其实很简单,遍历所有的BeanPostProcessor ,看是不是SmartInstantiationAwareBeanPostProcessor 对象(该接口是Spring AOP的顶级接口),不是(不需要AOP)直接返回原始bean。SmartInstantiationAwareBeanPostProcessor 提供了一个后门getEarlyBeanReference,该方法提前先调用了proxy bean的生成方法 wrapIfNecessary(),也就是说,AOP提前切入了。
0
 
 
问题4: 提前暴露出去的bean和最终生成的bean是同一个吗?
SmartInstantiationAwareBeanPostProcessor 接口做了强制规定,要么是同一个proxy对象,要么直接放回原始bean(不需要AOP的类)。
0
 
下面用AbstractAutoProxyCreator这个具体实现类的代码作进一步说明。 方法postProcessAfterInitialization() 加了一个判断,如果之前调用了getEarlyBeanReference(),完成了AOP,这里就不重复调用wrapIfNecessary()了(只是从earlyProxyReferences 做了remove),从而保证是同一个proxy对象。
0
 
 
问题5:很多文档说的循环依赖是通过三级缓存解决的,这个说法是咋回事?
 
上面详细介绍了singletonFactories 怎么暴露出去的,三级缓存就是DefaultSingletonBeanRegistry类里面的三个map,缓存核心逻辑见下段代码,先找singletonObjects,找不到再从earlySingletonObjects找,还是没有直接用singletonFactories 工厂创建(里面对singletonObjects加了锁,防止并发错误)。
0
 
代码实践:
为了证明以上说法,我们简单写一点代码加以验证。
代码://gitee.com/zfj321/spring-sourcecode-study
然后在下面位置打一个断点,进行跟踪。
0
 
 
参考资料: