Spring循环依赖
上次在拜读Spring揭秘的第二章时,依赖注入这个问题是SpringIOC的一步核心操作,但是在依赖注入的时候也发现了一个问题,在依赖注入的时候,如果Bean之间的属性引用产生了互相引用,那么在加载的时候就会出现循环依赖的经典Spring问题。(创建新的A时,发现要注入原型字段B,又创建新的B发现要注入原型字段A…)
Spring内部对于循环依赖是做出了一些解决方案的,首先肯定会帮你报个错,就像递归没有退出条件一样系统会抛出StackOverflow错误一样。Spring在遇到了这种情况时会抛出BeanCurrentlyInCreationException。
那么我们还是先回顾一下之前Spring的三种依赖注入:构造器注入、Setter注入、接口注入(该方式基本没人用了)。在官方文档中不允许基于构造器的循环依赖。在Spring2.5中就有了@Autowired自动注入。
那么Spring如何解决的循环依赖这个问题?我拜读了各位大佬的见解,很多都是说的使用一个三级缓存,这个三级缓存其实就是三个Map(singletonObjects(单例池容器);singletonFactories(映射创建Bean的原始工厂); earlySingletonObjects(初始化Bean))。
下面就基于IOC的Bean初始化的流程中的一部分进行Spring三级缓存处理循环依赖的说明(过段时间会写一篇IOC注入Bean的源码流程)先记住一个Bean注入的流程为:getSingleton()->doCreateBean()->populateBean()->addSingleton()
A注入时:
- 在doCreateBean()中会将A的工厂缓存到singletonObjects()这个Map中
- 之后进入populateBean()中加载A中的属性,发现A中有引用B这时开始注入B
- B重复1、2步骤
- 之后B来到了populateBean()中加载属性,发现B中有引用A,这时开始注入A
- A在getSingleton时发现之前有A工厂在singletonFactory中有缓存,于是就利用工厂A创建A到earlySingletonObjects中,之后B就在addSingleton中拿到A的属性,进入addSingleton()方法中,之后就注入了B。
- 之后A拿到了B就进入addSingleton,完成了A的注入。