前文
的时候提到过在这个过程中要解决循环依赖。
什么是循环依赖?
A类依赖B类,B类依赖A类。 这就是循环依赖。 如下就是一段在Spring中会造成循环依赖的代码
@Component
public class A {
private B b;
@Autowired
public A(B b) {
this.b = b;
}
}
@Component
public class B {
private A a;
@Autowired
public B(A a) {
this.a = a;
}
}
启动后会报错:error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
哪儿在抛错?
跟踪源码查看一下为何会报错。
由Spring之getBean知道了启动的时候会去创建所有非lazy的单实例bean
主要跟踪getSingleton: 1.没有已经加载好的实例,那么准备创建了。 2.创建前先使用beforeSingletonCreation(beanName);去检查是否【正在创建】,抛出循环依赖的异常。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
//关注:从【一级缓存】中拿【已经加载好的】bean实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
//关注:先检查一下是否已经在创建。 就是 在这里检查了循环依赖。如果没有就添加【正在创建】标志
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//关注:创建实例过程--调用createBean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
//关注:移出【正在创建】标志
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
但是为何会抛错呢?
debug跟一下。 发现在第getBean(“a”)的时候,会有如下步骤: 1.getBean(“a”)。2.标记A【正在创建】。 3.得到A的构造函数,尝试去创建A的实例。 4.在创建A的实例之前,要得到构造函数的参数B的实例。 5.getBean(“b”)。 6.标记B【正在创建】。 7.重复步骤2-3. 不过此时是得到B的构造函数,并尝试获取A的实例。 8.getBean(“a”) 。ps:注意,这里是第二次getBean(“a”)了。9.再次标记A【正在创建】中。—标记失败,抛出异常。
具体过程参考下图:
ps:网图改了一下
由此,知道为何构造注入会引起循环依赖的时候抛错。
如果对这个注入过程不熟悉的,可以参考我之前的Spring之getBean。
那么如何避免抛错呢?
1.允许循环依赖(默认是允许的)。① 2.使用非构造注入,如@Autowired写在成员变量或者setter方法上。 3.要有无参构造函数,或者是不包含被依赖的成员变量的构造函数(避免在一开始注入的时候就需要一个拥有完整成员变量的B)。
例如之前的例子:
开始A实例的创建 1.getBean(“a”)->标记A【正在创建中】。 2.创建A的实例的时候,用无参构造创建一个A的实例a。 3.将半成品(无成员变量)a放到三级缓存中。② 4.populate的时候,尝试注入成员变量b。
开始B的实例创建
5.getBean(“b”)创建一个B的实例>标记B【正在创建中】 6.B通过createBeanInstance创建实例后, 7.将半成品(无成员变量)b放到三级缓存中。 8. populate去注入成员变量a. 9.getBean(“a”)->getSingleton(“a”, true)->从一级缓存(singletonObjects)中取->取不到则从二级缓存(earlySingletonObjects)中取->取不到则从三级缓存(singletonFactories)中取->从三级缓存中取出ObjectFactory得到A的实例a,将a放入二级缓存,并将ObjectFactory从三级缓存中移出。③ 10.得到了a的实例(半成品),注入到b中。继续走完B创建。b实例的创建完成
继续A实例的创建 11.将完成品B的实例b,注入到A中。 继续走完A创建。
非构造注入整个流程
ps:偷来的图
①不允许循环依赖当然要报错
②将半成品(无成员变量)a放到三级缓存中
③从三级缓存中取出ObjectFactory得到A的实例a,将a放入二级缓存,并将ObjectFactory从三级缓存中移出
为何是三级缓存?
个人认为,第三级缓存的作用, 是留了一个钩子,方便【获取半成品实例】的时候做一些定制。 如下源码:实现SmartInstantiationAwareBeanPostProcessor#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;
}
参考资料