大致简述一下spring里bean的生命周期:
spring扫描class,获取beanDefinition对象
↓
根据beanDefinition对象生成bean
↓
根据class推断构造方法,反射生成一个原始对象
↓
为这个原始对象填充属性(依赖注入)
↓
如果存在aop则生成一个代理对象
↓
把最终生成的对象放在singletonObjects单例池中
步入正题
什么是循环依赖?
比如 spring在加载A,在构造完A类后为A类填充属性,发现A类中依赖了B类,spring再去加载B类(前提是B类没有被加载过),构造完B类后为B类填充属性,发现B类里面依赖了A类,但此时A类并没有完全经过整个生命周期,不在singletonObjects单例池中,那么Spring无法拿到A填充给B类,这时就会导致循环依赖的问题,类似死锁。
解决大多数人可能会想到给加一个缓存作为中间人不就行了。好那我们假如这个中间人为earlySingletonObjects单例池:
创建A
↓
将A放入earlySingletonObjects中
↓
A依赖注入,需要注入B
↓
创建B
↓
将B放入earlySingletonObjects中
↓
B依赖注入,需要注入A
↓
判断earlySingletonObjects中是否有A
↓
存在,B对A依赖注入完成
↓
将B放入singletonObjects
↓
A依赖注入完成
↓
将A放入singletonObjects
这样一看好像确实没有什么问题,但其实别忘了Spring的两大特性IOC和AOP
如果A中存在aop,那么A最后在依赖注入完成后往singletonObjects放入的是一个代理对象,但是从上面流程我们看到B依赖的A是earlySingletonObjects中的A,而存放在earlySingletonObjects中的A还没有经过aop生成代理对象,是一个原始对象。那么这样实际上已经违反了spring的IOC控制反转的原则,同时存在了两个不同的A对象。
现在来看看Spring是怎么做的呢
Spring解决循环依赖三级缓存
- singletonObjects :缓存经过完整生命周期的bean
- earlySingletonObjects :缓存未经过完整生命周期的bean
- singletonFactories :缓存了一个ObjectFactory,一个lambda表达式
其实还有一个缓存 earlyProxyReferences 用来记录某个原始对象是否进行过AOP
前面singletonObjects和earlySingletonObjects我们都知道是干嘛的,那么singletonFactories是存放什么呢,会存放一个lambda表达式
() -> getEarlyBeanReference(beanName, mbd, bean)
getEarlyBeanReference这个方法我们看下源码:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
他会实现SmartInstantiationAwareBeanPostProcessor 方法中的getEarlyBeanReference()方法:
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
目前整个spring里面只有AbstractAutoProxyCreator去实现了getEarlyBeanReference这个方法。我们再来看下:
创建A
↓
为A对象生成一个objectFactory放入singletonFactories中
↓
A依赖注入,需要注入B
↓
创建B
↓
为B对象生成一个objectFactory放入singletonFactories中
↓
B依赖注入,需要注入A
↓
先从earlySingletonObjects中查找是否存在A,存在则直接注入完成
↓
不存在,则通过三级缓存池singletonFactories获取A的objectFactory生成对象,
如果A存在AOP则提前对A进行AOP,将生成的结果放入二级缓存池earlySingletonObjects中,
再去除singletonFactories中A的objectFactory
↓
B对A依赖注入完成,B完成整体bean的生命周期,放入一级缓存池singletonObjects中
↓
A对B依赖注入完成,A完成整体bean的生命周期,放入一级缓存池singletonObjects中
结语
以上流程是大致的流程,真正的好代码是需要亲自去看去理解的。
当然Spring解决循环依赖的方法可以解决大多数循环依赖,但是还是会存在依赖深度较复杂,Spring无法解决,这个时候可以在导致循环依赖的地方加上@Lazy注解,对改依赖进行懒加载,只有使用到改依赖时才会进行加载。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)