前言:
// 疑问点: 先进行 dependon 判断
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
这里先简单记录下 现在理解的 循环依赖的大致流程:
1、depende-on 标签的情况
<bean id="aService" class="com.zzf.spring.dependent.AService" depends-on="bService"/>
<bean id="bService" class="com.zzf.spring.dependent.BService" depends-on="aService"/>
注: depends-on适用于表面上看起来两个bean之间没有使用属性之类的强连接的bean,但是两个bean又确实存在前后依赖关系的情况,使用了depends-on的时候,依赖他人的bean是先于被依赖bean销毁的。 一般不会这么使用。
也就是这样配置的情况,才会抛出 BeanCreationException 异常。
if (isDependent(beanName, dep)) {// 判断返回 true, 抛出循环依赖的exception
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
2、正确的 xml 配置的循环依赖 demo
<bean id="aService" class="com.zzf.spring.dependent.AService">
<property name="bService" ref="bService"/>
</bean>
<bean id="bService" class="com.zzf.spring.dependent.BService">
<property name="aService" ref="aService"/>
</bean>
3、注解的方式解决循环依赖
@Service
public class Aservice {
@Autowired
private BService service;
}
@Service
public class BService {
@Autowired
private Aservice aservice;
}
都说这段是 解决 循环依赖的 关键所在:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
这里主要涉及到3个缓存, singletonObjects,earlySingletonObjects, singletonFactories。
- singletonObjects: 单例对象的 cache
- singletonFactories: 单例对象工厂的 cache
- earlySingletonObjects: 提前曝光的单例对象的 cache。(这是关键)
这里只考虑 A--B --A的情况:
Object sharedInstance = getSingleton(beanName);
第一次 getBean(A)的时候, 返回是 null, 会走如下流程:
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
在 createBean -> doCreate中有如下: addSingletonFactory() 提前 曝光当前类 工厂,到 singletonFactory中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
然后执行 protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) 进行 属性的 赋值。 在进行 B的属性赋值中, 发现B还没有初始化, 则会去 调用 BeadFactory.getBean(B) 进行 B的初始化。
调用B的过程中,和A类似, 也会 提前 在singletonFactory 中曝光, 然后在 populateBean 中,注入 A属性值时, 因为A未初始化,再次 去请求 getBean(A), 这次 在 getSingleton()中,因为 A提前曝光,所以在getSingleton 中 返回 A(可能未完全初始化),最终调用 getObjectForBeanInstance 方法,返回 完全实例话的 bean A, 然后注入到B 中,并完成B的 初始化, bean都会 放进singletonObjects 缓存中。
TODO: 在 populateBean 中怎么检测 到 properties,这块还需 仔细的去debug,还没完全理清楚。
参考资料:http://cmsblogs.com/?p=2887,看了多次,总结的很好。