循环依赖
循环依赖
Spring 内部维护了三个 Map,也就是常说的三级缓存
1 | /** Cache of singleton objects: bean name to bean instance. */ |
循环依赖分为有 AOP 的循环依赖,和没有 AOP 的循环依赖
Spring 解决循环依赖是有前置条件的
- 出现循环依赖的 Bean 必须要是 单例
- 依赖注入的方式不能 全是构造器注入 的方式
- A 中注入 B 的方式为
setter
方法,B 中注入 A 的方式为构造器,这种情况能被解决 - B 中注入 A 的方式为
setter
方法,A 中注入 B 的方式为构造器,这种情况不能被解决- 在创建 Bean 的时候默认是按照 自然排序 来进行创建的,所以第一步 Spring 会去创建 A
- A 中注入 B 的方式为
步骤
创建 Bean 的过程中分为 三步
- 实例化
AbstractAutowireCapableBeanFactory
中的createBean
方法,即createBeanInstance
方法
- 属性注入
AbstractAutowireCapableBeanFactory
的populateBean
方法
- 初始化
AbstractAutowireCapableBeanFactory
的initializeBean
方法
从 getBean( A )
即 doGetBean
方法开始
1 | // AbstractBeanFactory |
doGetBean
先 尝试 从缓存中获取,若获取不到,就创建
1 | protected <T> T doGetBean(final String name, final Class<T> requiredType, |
从缓存尝试拿A
首先到缓存中尝试去获取 Bean( A ),即 getSingleton(beanName, true)
1 | Object sharedInstance = getSingleton(beanName); |
调用 getSingleton( 从缓存 ) 方法
1 | protected Object getSingleton(String beanName, boolean allowEarlyReference) { |
但是第一次来缓存里肯定没有 A,就会走下面的 getSingleton(beanName, singletonFactory)
方法
- 因为 二参 是匿名函数,即 lambda,到 getSingleton 调用它的时候才执行
1 | if (mbd.isSingleton()) { |
getSingleton( 从创建拿A )
先看前半部分:
1 | public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { |
执行匿名函数,先执行 createBean
,即执行 doCreateBean
- 执行
createBeanInstance
拿到 Bean( A ) 实例后 - 看到
earlySingletonExposure
为true
- 然后就会执行
addSingletonFactory
,把 新的 Bean 实例( A ) 包装成工厂,添加到 三级缓存 singletonFactory
1 | // AbstractAutowireCapableBeanFactory |
重点是
earlySingletonExposure
为true
然后执行了
addSingletonFactory
,把 新的 Bean 实例( A )包装成工厂添加到三级缓存 singletonFactoryaddSingletonFactory
的二参是匿名函数,里面是getEarlyBeanReference
- 注意:在 没有 AOP!!! 的情况下,getEarlyBeanReference 返回的工厂还是现在的 Bean 实例( A )
```java
// 二参是匿名函数
// 在没有 AOP 的情况下,getEarlyBeanReference 返回工厂的还是现在的 Bean 实例
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
// Assert..
synchronized (this.singletonObjects) {
// 此时 A 实例化了,但还没完成初始化
// 所以一级缓存单例池 singletonObjects 里面害没有 A
if (!this.singletonObjects.containsKey(beanName)) {
// 将 A 的工厂加入到三级缓存
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
然后 `doCreateBean` 还没完,还有 `populateBean` 属性注入
- 就会发现 A 里面还有个 B,然后 `getBean(B)`,**开始套壳了!!**
```java
// AbstractAutowireCapableBeanFactory
protected Object doCreateBean(
final String beanName, final RootBeanDefinition mbd,
final @Nullable Object[] args)
throws BeanCreationException {
// 实例化
// addSingletonFactory 加入三级缓存
Object exposedObject = bean;
try {
// 属性赋值,会发现 B,然后 getBean(B)
populateBean(beanName, mbd, instanceWrapper);
// 就此打住,先不看下面
// 初始化
// exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// ...
return exposedObject;
}
套壳开始(A拿B)
getBean(B)
-> doGetBean
还是先执行 getSingleton( 从缓存获取 )
,发现 B 没实例化
然后 createBean
1 | if (mbd.isSingleton()) { |
createBean
即 doCreateBean
- 先
createBeanInstance
创建 B 实例 - 然后执行
addSingletonFactory
加入三级缓存
1 | if (earlySingletonExposure) { |
然后属性注入,发现 有个 A
然后 getBean( A )
又套壳(B拿A,成功了)
又回到 doGetBean
中的 getSingleton( 从缓存中获取 )
但是这次发现 A 就在三级缓存中!!!
- 拿到 A
- 把 A 放进 二级缓存
earlySingletonObjects
中( 表示 A 还未完全初始化,注意 未完全!!) - 然后把 A 从三级缓存拿掉
1 | protected Object getSingleton(String beanName, boolean allowEarlyReference) { |
拿到 A 了,就直接返回,然后 B 完成属性注入,完成初始化
为什么 B 拿到的是 半残 的 A,但是没出问题?
- 因为 B 拿的是 A 的 引用,之后 B 完成初始化还得回传给 A
回到A拿B
B 完成初始化后,回到 A 拿 B 的时候的 getSingleton
- 当 B 完成实例化,即完成对 A 的属性注入后
- 把 B 加入到 一级缓存 中,即 单例池
- 把 B 从 三级缓存工厂 中 移除
- 把 B 从 二级工厂 移除
- 这标志着 B 彻底完成初始化!
1 | public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { |
A 完成属性注入,完成初始化
回到我们拿A
回到我们自己( 容器 )拿 A 的时候,getSingleton
- 当 A 完成实例化,即完成对 B 的属性注入后
- 把 A 加入到一级缓存中,即单例池
- 把 A 从三级缓存工厂中移除
- 把 A 从二级工厂移除
- 这标志着 A 彻底完成初始化!
1 | public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { |
结束!!
getEarlyBeanReference
这里就是上面说到,即将注入到 B 中的 A 是通过 getEarlyBeanReference 方法 提前暴露 出去的一个工厂对象,还不是一个完整的 Bean
1 | protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { |
getEarlyBeanReference 方法实际上就是调用了后置处理器的 getEarlyBeanReference 方法,而真正实现了这个方法的后置处理器只有一个,就是通过 @EnableAspectJAutoProxy 注解导入的 AnnotationAwareAspectJAutoProxyCreator
也就是说如果在不考虑 AOP 的情况下,上面的代码等价于
1 | protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { |
也就是说这个工厂啥都没干,直接将实例化阶段创建的对象返回了
在没 AOP 的情况下,三级缓存没毛用
在有 AOP 的情况下,getEarlyBeanReference 生成的工厂是经过包装的,不再是原来那个 A 或 B 了,因为 AOP 了
摘自大佬的一张图: