Spring IoC - 循环依赖 (2)

这里在遍历后置处理器的过程中,会调用到AbstractAutoProxyCreator的postProcessAfterInitialization方法,此方法会判断A是否被代理,如果被代理会创建代理对象并返回,之后将原有A对象从三级缓存中删除,并将A的代理对象加入到二级缓存earlySingletonObjects中,之后将A的代理对象注入给B

B执行initializeBean方法,调用后置处理器及afterProperties方法,这里提到后置处理器,同样会判断B是否被代理,如果被代理则会创建B的代理对象并返回

B创建结束之后,会回到getSingleton---2方法,调用addSingleton(beanName, singletonObject);方法,如下

protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }

这里会将B从三级缓存中删除,并加入到一级缓存中

A执行initializeBean方法,进行初始化,初始化完成

回到getSingleton--2,执行DefaultSingletonBeanRegistry#addSingleton

protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }

将A从二级缓存中删除,并加入到一级缓存中

从上面步骤可以看出,三级缓存分别用于存放下面三类对象

一级缓存singletonObjects

完全创建好的对象,如果被代理,则存放代理对象

二级缓存earlySingletonObjects

未完全创建好的代理对象

三级缓存singletonFactories

只进行了实例化,未进行属性注入和初始化的对象

3.4 AoP的考虑

如上在有循环依赖的情况下,假设A被代理,那么需要将A的代理对象注入给B,这时通过getSingleton方法从三级缓存获取对象的过程中,由于ObjectFactory的getObject方法被重写为AbstractAutowireCapableBeanFactory#getEarlyBeanReference方法,这时会触发后置处理器的执行,会调用AbstractAutoProxyCreator的postProcessAfterInitialization方法,并返回代理对象,之后将代理对象返回用于注入,并放入二级缓存,如果A和除了B的其他对象也构成循环依赖,之后直接从二级缓存中获取A的代理对象即可

在没有循环依赖的情况下,不会使用到二级缓存,如果A被代理,那么A会在完全创建后,在调用后置处理器序列时,会调用AbstractAutoProxyCreator的postProcessAfterInitialization方法,并返回代理对象

从上可以看出,

Spring的机制是尽量让代理对象靠后创建,也即在没有循环依赖时在对象完全创建后再创建代理对象

在延迟创建代理对象的机制下,必须有二级缓存,这样在从三级缓存中获取时,会调用ObjectFactory方法,其又调用getEarlyBeanReference方法完成代理对象创建,之后二级缓存用于存储代理对象,而一级缓存用于存放完全创建完成的对象

Spring中,如果调用某个代理对象a的方法,其中又调用了代理对象b的方法,而不是对象b的方法

# 参考

Spring循环依赖三级缓存是否可以减少为二级缓存? - SegmentFault 思否

高频面试题:Spring 如何解决循环依赖? - 知乎 (zhihu.com)

Spring-bean的循环依赖以及解决方式_惜暮-CSDN博客_spring 循环依赖

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsspdy.html