转载

SpringBoot IoC(5)循环依赖与实例化总结

@Configuration
@RequiredArgsConstructor
public class Adam {
    private final Eve eve;
}
复制代码
@RequiredArgsConstructor
@Configuration
public class Eve {
    private final Adam adam;
}
复制代码
AbstractAutowireCapableBeanFactory->createBeanInstance():
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }
复制代码

在选择构造器注入的时候,会遍历字段,根据beanClass反推beanName,然后实例化。 一路debug,最终找到了抛出异常的调用栈:

DefaultSingletonBeanRegistry->getSingleton():
    beforeSingletonCreation(beanName);
DefaultSingletonBeanRegistry->beforeSingletonCreation():
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
复制代码

与之对应的是afterSingletonCreation方法

if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
        throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
    }
复制代码

结论

singletonsCurrentlyInCreation是一个Set集合,表示当前正在创建的bean名称,创建完成后,会移除。

原来,当同一个bean未完成实例化,又再一次实例化时,singletonsCurrentlyInCreation.add(beanName)返回false,进而抛出了异常,导致程序报错

字段注入时

@Component
public class Adam {
    @Autowired
    private eve;
}
复制代码
@Component
public class Eve {
    @Autowired
    private Adam adam;
}
复制代码

这样写发现并没有报错,一路debug,发现是这段代码起的作用:

AbstractBeanFactory->doGetBean():
    Object sharedInstance = getSingleton(beanName);
AbstractBeanFactory->getSingleton():
    return getSingleton(beanName, true);
AbstractBeanFactory->getSingleton(): 
    // 此时singletonObjects未完成,所以肯定是null
    Object singletonObject = this.singletonObjects.get(beanName);
    // 根据前面的分析,singletonsCurrentlyInCreation肯定包含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);
                }
            }
        }
    }
复制代码

此时发现, earlySingletonObjects.get(beanName) 为空, singletonFactories.get(beanName) 获取到了值,继而获取到了singletonObject(这里看出 earlySingletonObjects创建,对应的singletonFactory会移除 )。重新debug,发现是这里给singletonFactories赋了值:

AbstractAutowireCapableBeanFactory->doCreateBean():
    if (earlySingletonExposure) {
        if (logger.isTraceEnabled()) {
            logger.trace("Eagerly caching bean '" + beanName +
                "' to allow for resolving potential circular references");
        }
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
DefaultSingletonBeanRegistry->addSingletonFactory():
    synchronized (this.singletonObjects) {
        if (!this.singletonObjects.containsKey(beanName)) {
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
复制代码

这段代码是在实例化完成之后进行的,也就是说,当构造器注入的时候,并没有添加到singletonFactories,所以 getSingleton(beanName) 返回空,进行了第二次的实例化,从而导致报错(这里看出 singletonFactories创建,对应的earlySingletonObjects会移除 )。继续debug,最终singletonFactories和earlySingletonObjects都被清除了:

DefaultSingletonBeanRegistry->getSingleton():
    addSingleton(beanName, singletonObject);
DefaultSingletonBeanRegistry->addSingleton():
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
复制代码

当singletonObjects创建的时候,earlySingletonObjects和singletonFactories的使命就完成了~

结论

对于字段注入,IoC容器使用了singletonFactories和earlySingletonObjects来预防循环依赖。

原文  https://juejin.im/post/5f0db861e51d453476713f06
正文到此结束
Loading...