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

1,911 阅读5分钟

所谓的循环依赖,是指在实例化A类时,注入B类,实例化B类时,注入A类。

依赖注入分为构造器注入和字段注入,下面依次对这两种情况分析。

构造器注入时

@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,发现调用的是getBean(String name),最终找到了抛出异常的调用栈:

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 eve;
}
@Component
public class Eve {
    @Autowired
    private Adam adam;
}

这样写发现并没有报错,一路debug,调用的仍是getBean(String name),但是起始位置的这行代码返回了对象:

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来预防循环依赖。

附录

bean的实例化过程

  1. 单例对象缓存中有则直接返回
  2. 创建mergedBeanDefinitions,返回RootBD
  3. 存在@DependsOn注解时,先实例化
  4. 根据不同的作用域作不同处理,假设是单例,那么执行beforeSingletonCreation()方法
  5. 调用各后置处理器的postProcessBeforeInstantiation(beanClass, beanName)方法(InstantiationAwareBeanPostProcessor接口实现类),如果有AnnotationAwareAspectJAutoProxyCreator这个后置处理器,此时将会提前解析AoP方法,如果返回有值,调用各后置处理器的postProcessAfterInitialization(result, beanName)方法(BeanPostProcessor接口实现类,它是所有后置处理器的父类),结束实例化
  6. 根据beanName获得beanClass,完成实例化(此处完成构造器注入)
  7. 调用各后置处理器的postProcessMergedBeanDefinition(mbd, beanType, beanName)方法(MergedBeanDefinitionPostProcessor接口实现类),解析自动注入的字段,设置singletonFactories和registeredSingletons
  8. 完成依赖注入(populateBean(beanName, mbd, instanceWrapper)),根据autowireMode决定要实例化的对象,调用各后置处理器的postProcessProperties(pvs, bw.getWrappedInstance(), beanName)方法(InstantiationAwareBeanPostProcessor接口实现类),如果在自动注入模式过程后,有要自动注入的对象,则调用set方法注入
  9. 完成初始化(initializeBean(beanName, exposedObject, mbd)
    1. 调用各后置处理器的postProcessBeforeInitialization(result, beanName)方法(BeanPostProcessor接口实现类,它是所有后置处理器的父类),当为CommonAnnotationBeanPostProcessor的时候,会实现@PostConstruct 标记的方法(利用反射method.invoke((target, args))实现);当为AnnotationAwareAspectJAutoProxyCreator的时候,执行AoP流程;当为ConfigurationPropertiesBindingPostProcessor的时候,将注解ConfigurationProperties与配置文件中前缀相符的属性赋值到对应的bean对象的字段
    2. 调用invokeInitMethods(beanName, wrappedBean, mbd)方法,如果实现了InitializingBean接口,会执行afterPropertiesSet方法
    3. 调用invokeCustomInitMethod(beanName, bean, mbd)方法,如果bean指定了initMethod属性,会执行对应名称的方法
    4. 调用各后置处理器的postProcessAfterInitialization(result, beanName)方法(BeanPostProcessor接口实现类,它是所有后置处理器的父类),当为ApplicationListenerDetector的时候,如果当前bean是ApplicationListener的实现类,会加入到应用上下文的监听器集合中
  10. 当bean满足摧毁条件时,先行记录到disposableBeans成员变量中(registerDisposableBeanIfNecessary(beanName, bean, mbd)),以下几种满足摧毁条件
    1. DisposableBean或AutoCloseable接口实现类
    2. @Bean指定的destroyMethod
    3. 调用各后置处理器的requiresDestruction(bean)方法返回为true(DestructionAwareBeanPostProcessor接口实现类),当为CommonAnnotationBeanPostProcessor的时候,会找到@PreDestroy标记的方法
  11. 完成实例化,执行afterSingletonCreation(beanName)方法,销毁singletonFactories和registeredSingletons
  12. 调用getObjectForBeanInstance(sharedInstance, name, beanName, mbd),如果实例化bean是FactoryBean实现类则调用getObject()返回对象,否则返回实例化完成的bean
  13. 所有bean实例化完成以后,如果有bean是SmartInitializingSingleton的实现类,调用afterSingletonsInstantiated()方法

附:在bean的实例化过程中,如果被捕捉到BeansException异常,将会摧毁所有实例化完成的bean,启动失败。

大致过程为:

遍历map结构的disposableBeans,它的value是DisposableBeanAdapter对象引用,成员变量beanPostProcessors是实现DestructionAwareBeanPostProcessorrequiresDestruction(Object bean)方法为true的后置处理器集合

  1. 遍历beanPostProcessors,调用后置处理器的postProcessBeforeDestruction(this.bean, this.beanName)方法,当为CommonAnnotationBeanPostProcessor的时候,会利用反射执行@PreDestroy标记的方法
  2. 如果实现了DisposableBean接口,调用其destroy方法
  3. 如果bean指定了destroyMethod属性,执行对应名称的方法
  4. 如果bean没有指定destroyMethod属性,看是否实现了AutoCloseable接口,调用其close方法
  5. 代码位于DisposableBeanAdapter->destroy()

关于FactoryBean

如果一个bean实现了FactoryBean接口,那么,getBean(String name)返回的是bean类下其getObject()返回的对象,如果name前加上前缀&,那么返回的仍然是该bean