举个例子
@Component public class A { // A中注入了B @Autowired private B b; } @Component public class B { // B中也注入了A @Autowired private A a; }
上面这种现象产生了循环依赖
1.什么情况下循环依赖可以被处理?
在回答这个问题之前首先要明确一点,Spring解决循环依赖是有前置条件的
-
出现循环依赖的Bean必须要是单例
-
依赖注入的方式不能全是构造器注入的方式(很多博客上说,只能解决setter方法的循环依赖,这是错误的)
关于循环依赖的解决方式应该要分两种情况来讨论?
-
简单的循环依赖(没有AOP)
-
结合了AOP的循环依赖
首先按照顺序创建A的过程实际上就是调用getBean方法,这个方法有两层含义
1.创建一个新的Bean 2.从缓存中获取到已经被创建的对象
我们现在分析的是第一层含义,因为这个时候缓存中还没有A调用getSingleton(beanName) 首先调用getSingleton(a)方法,这个方法又会调用getSingleton(beanName, true)
public Object getSingleton(String beanName) { return getSingleton(beanName, true); }
getSingleton(beanName, true)
这个方法实际上就是到缓存中尝试去获取Bean,整个缓存分为三级
-
singletonObjects
,一级缓存,存储的是所有创建好了的单例Bean -
earlySingletonObjects
,完成实例化,但是还未进行属性注入及初始化的对象 -
singletonFactories
,提前暴露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象
A在创建过程中需要B,于是A先将自己放到三级缓存里面,去实例化B
B实例化的时候发现需要A,于是B先查一级缓存,没有再查二级缓存,还是没有,再查三级缓存,找到了A;然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A
B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态);然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A放入到一级缓存中
二级缓存行不行,为什么用三级缓存呢?
二级可以,对于创建的bean不需要AOP代理的对象二级缓存是可以的
但是如果有代理对象,则不行
因为我们期望的注入的是一个被代理后的对象,而不是一个原始对象! 所以这里并不能够直接将一个原始对象放置到缓存中,我们可以直接进行判断(就是用 objectFactory实际上就是一个对应的lamba表达式),如果需要Aop的话进行代理之后放入缓存!
但是Aop的操作是在哪里做的?
是在Spring声明周期的最后一步来做的!如果我们进行判断创建的话,Aop的代理逻辑就会在创建实例的时候就进行Aop的代理了,这明显是不符合Spring对于Bean生命周期的定义的! 所以,Spring重新定义了一个缓存 singletonFactories 用来存放一个Bean的工厂对象,创建的对象之后,填充属性之前会把创建好的对象放置到 singletonFactories 缓存中去,并不进行实例化,只有在发生了循环引用,或者有对象依赖他的时候,才会调用工厂方法返回一个代理对象,从而保证了Spring对于Bean生命周期的定义!