热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Spring5IOC容器解析——单例循环依赖的解决

什么是循环依赖循环依赖其实就是循环引用,也就是两个或者两个以上的bean互相持有对方,最终形成闭环。A依赖B,B又依赖A,它们之间形成了循环依赖。或者是A依赖

什么是循环依赖

循环依赖其实就是循环引用,也就是两个或者两个以上的bean互相持有对方,最终形成闭环。A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。或者是 A 依赖 B,B 依赖 C,C 又依赖 A。它们之间的依赖关系如下:

Spring5IOC容器解析——单例循环依赖的解决

注意,这里不是函数的循环调用,是对象的相互依赖关系。循环调用其实就是一个死循环,除非有终结条件。

Spring中循环依赖场景有:

  • 1、构造器的循环依赖
  • 2、field属性的循环依赖

其中,构造器的循环依赖问题是无法解决,只能拋出BeanCurrentlyInCreationException异常,在解决属性循环依赖时,spring采用的是提前暴露对象的方法。

怎么检测是否存在循环依赖

检测循环依赖相对比较容易,Bean在创建的时候可以给该Bean打标,如果递归调用回来发现正在创建中的话,即说明了循环依赖了。

三级缓存的介绍,用于解决单例Bean的循环依赖

/** Cache of singleton objects: bean name to bean instance. */
//一级缓存:单例对象缓存池,beanName->Bean,其中存储的就是实例化,属性赋值成功之后的单例对象
private final Map singletOnObjects= new ConcurrentHashMap(256);

/** Cache of singleton factories: bean name to ObjectFactory. */
//三级缓存:单例工厂的缓存,beanName->ObjectFactory,添加进去的时候实例还未具备属性
// 用于保存beanName和创建bean的工厂之间的关系map,单例Bean在创建之初过早的暴露出去的Factory,
// 为什么采用工厂方式,是因为有些Bean是需要被代理的,总不能把代理前的暴露出去那就毫无意义了
private final Map> singletOnFactories= new HashMap(16);

/** Cache of early singleton objects: bean name to bean instance. */
//二级缓存:早期的单例对象,beanName->Bean,其中存储的是实例化之后,属性未赋值的单例对象
// 执行了工厂方法生产出来的Bean,bean被放进去之后,
// 那么当bean在创建过程中,就可以通过getBean方法获取到
private final Map earlySingletOnObjects= new HashMap(16);

根据缓存变量上面的注释,大家应该能大致了解他们的用途。我这里简单说明一下吧:

缓存 用途
singletonObjects 用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用。
earlySingletonObjects 提前曝光的单例cache,存放原始的 bean 对象(尚未填
充属性),用于解决循环依赖。
singletonFactories 存放 bean 工厂对象,用于解决循环依赖。

Spring创建Bean的流程

Spring5IOC容器解析——单例循环依赖的解决
Spring IOC 容器中获取 bean 实例的流程
Spring5IOC容器解析——单例循环依赖的解决

对Bean的创建最为核心三个方法解释如下:

  • createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象
  • populateBean:填充属性,这一步主要是对bean的依赖属性进行注入(@Autowired)
  • initializeBean:回到一些形如initMethod、InitializingBean等方法

从对单例Bean的初始化可以看出,循环依赖主要发生在第二步(populateBean),也就是field属性注入的处理。

Spring怎么解决循环依赖,setter方式单例

Spring的循环依赖的理论依据基于Java的引用传递,当获得对象的引用时,对象的属性是可以延后设置的。(但是构造器必须是在获取引用之前)。

循环依赖解决方式: 三级缓存

由refresh()为入口切入, 这里只分析单例bean创建流程:

  • 1、AbstractBeanFactory.getBean为入口 并委托 AbstractBeanFactory.doGetBean创建。

  • 2、AbstractBeanFactory.doGetBean 会首先从AbstractBeanFactory.getSingleton中获取缓存的bean对象, 如果不存在则调用抽象方法createBean, 即子类实现的AbstractAutowireCapableBeanFactory.createBean方法。

  • 3、AbstractAutowireCapableBeanFactory.createBean方法触发doCreateBean依次调用以下方法实现bean创建过程:

    • A、createBeanInstance: 实例化bean, 如果需要依赖其他对象则首先创建其他对象(发生循环依赖的地方)
    • B、addSingletonFactory: 将实例化bean加入三级缓存
    • C、populateBean: 初始化bean, 如果需要依赖其他对象则首先创建其他对象(发生循环依赖的地方)
    • D、initializeBean
    • E、registerDisposableBeanIfNecessary

如果是构造函数注入的话在createBeanInstance方法中会调用autowireConstructor

  • 1、AbstractAutowireCapableBeanFactory.autowireConstructor使用构造函数进行实例化。

  • 2、最终调用 ConstructorResolver.autowireConstructor 和 ConstructorResolver.resolveConstructorArguments 进行实例化已经解析构造参数。

  • 3、调用BeanDefinitionValueResolver.resolveValueIfNecessary 和 BeanDefinitionValueResolver.resolveReference 模版类解析构造参数。

步骤配上代码:

1、AbstractBeanFactory.getBean为入口 并委托 AbstractBeanFactory.doGetBean创建。

@Override
public Object getBean(String name) throws BeansException {
    // 获取name对应的bean实例,如果不存在,则创建一个
    return doGetBean(name, null, null, false);
}

protected  T doGetBean(final String name, @Nullable final Class requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    // 1.解析beanName,主要是解析别名、去掉FactoryBean的前缀“&”
    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    // 2.尝试从缓存中获取beanName对应的实例
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        // 3.如果beanName的实例存在于缓存中
        if (logger.isTraceEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        // 3.1 返回beanName对应的实例对象(主要用于FactoryBean的特殊处理,普通Bean会直接返回sharedInstance本身)
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // Fail if we're already creating this bean instance:
        // We're assumably within a circular reference.
        // 4.scope为prototype的循环依赖校验:如果beanName已经正在创建Bean实例中,而此时我们又要再一次创建beanName的实例,则代表出现了循环依赖,需要抛出异常。
        // 例子:如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // Check if bean definition exists in this factory.
        // 5.获取parentBeanFactory
        BeanFactory parentBeanFactory = getParentBeanFactory();
        // 5.1 如果parentBeanFactory存在,并且beanName在当前BeanFactory不存在Bean定义,则尝试从parentBeanFactory中获取bean实例
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            // 5.2 将别名解析成真正的beanName
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                        nameToLookup, requiredType, args, typeCheckOnly);
            }
            // 5.3 尝试在parentBeanFactory中获取bean对象实例
            else if (args != null) {
                // Delegation to parent with explicit args.
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }

        if (!typeCheckOnly) {
            // 6.如果不是仅仅做类型检测,而是创建bean实例,这里要将beanName放到alreadyCreated缓存
            markBeanAsCreated(beanName);
        }

        try {
            // 7.根据beanName重新获取MergedBeanDefinition(步骤6将MergedBeanDefinition删除了,这边获取一个新的)
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            // 7.1 检查MergedBeanDefinition
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            // 8.拿到当前bean依赖的bean名称集合,在实例化自己之前,需要先实例化自己依赖的bean
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                // 8.1 遍历当前bean依赖的bean名称集合
                for (String dep : dependsOn) {
                    // 8.2 检查dep是否依赖于beanName,即检查是否存在循环依赖
                    if (isDependent(beanName, dep)) {
                        // 8.3 如果是循环依赖则抛异常
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // 8.4 将dep和beanName的依赖关系注册到缓存中
                    registerDependentBean(dep, beanName);
                    try {
                        // 8.5 获取dep对应的bean实例,如果dep还没有创建bean实例,则创建dep的bean实例
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // Create bean instance.
            // 9.针对不同的scope进行bean的创建
            if (mbd.isSingleton()) {
                // 9.1 scope为singleton的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        // 9.1.1 创建Bean实例
                        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;
                    }
                });
                // 9.1.2 返回beanName对应的实例对象
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                // 9.2 scope为prototype的bean创建
                Object prototypeInstance = null;
                try {
                    // 9.2.1 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
                    beforePrototypeCreation(beanName);
                    // 9.2.2 创建Bean实例
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    // 9.2.3 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
                    afterPrototypeCreation(beanName);
                }
                // 9.2.4 返回beanName对应的实例对象
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                // 9.3 其他scope的bean创建,可能是request之类的
                // 9.3.1 根据scopeName,从缓存拿到scope实例
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    // 9.3.2 其他scope的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
                    Object scopedInstance = scope.get(beanName, () -> {
                        // 9.3.3 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
                        beforePrototypeCreation(beanName);
                        try {
                            // 9.3.4 创建bean实例
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            // 9.3.5 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
                            afterPrototypeCreation(beanName);
                        }
                    });
                    // 9.3.6 返回beanName对应的实例对象
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }
        }
        catch (BeansException ex) {
            // 如果创建bean实例过程中出现异常,则将beanName从alreadyCreated缓存中移除
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // Check if required type matches the type of the actual bean instance.
    // 10.检查所需类型是否与实际的bean对象的类型匹配
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            // 10.1 类型不对,则尝试转换bean类型
            T cOnvertedBean= getTypeConverter().convertIfNecessary(bean, requiredType);
            if (cOnvertedBean== null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            if (logger.isTraceEnabled()) {
                logger.trace("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    // 11.返回创建出来的bean实例对象
    return (T) bean;
}

2、AbstractBeanFactory.doGetBean 会首先从AbstractBeanFactory.getSingleton中获取缓存的bean对象, 如果不存在则调用抽象方法createBean, 即子类实现的AbstractAutowireCapableBeanFactory.createBean方法。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    /** Cache of singleton objects: bean name to bean instance. */
    //一级缓存:单例对象缓存池,beanName->Bean,其中存储的就是实例化,属性赋值成功之后的单例对象
    private final Map singletOnObjects= new ConcurrentHashMap(256);

    /** Cache of singleton factories: bean name to ObjectFactory. */
    //三级缓存:单例工厂的缓存,beanName->ObjectFactory,添加进去的时候实例还未具备属性
    // 用于保存beanName和创建bean的工厂之间的关系map,单例Bean在创建之初过早的暴露出去的Factory,
    // 为什么采用工厂方式,是因为有些Bean是需要被代理的,总不能把代理前的暴露出去那就毫无意义了
    private final Map> singletOnFactories= new HashMap(16);

    /** Cache of early singleton objects: bean name to bean instance. */
    //二级缓存:早期的单例对象,beanName->Bean,其中存储的是实例化之后,属性未赋值的单例对象
    // 执行了工厂方法生产出来的Bean,bean被放进去之后,
    // 那么当bean在创建过程中,就可以通过getBean方法获取到
    private final Map earlySingletOnObjects= new HashMap(16);

    /** Names of beans that are currently in creation. */
    //三级缓存是用来解决循环依赖,而这个缓存就是用来检测是否存在循环依赖的
    private final Set singletOnsCurrentlyInCreation=
            Collections.newSetFromMap(new ConcurrentHashMap(16));

    /** Names of beans currently excluded from in creation checks. */
    //直接缓存当前不能加载的bean
    private final Set inCreatiOnCheckExclusions=
            Collections.newSetFromMap(new ConcurrentHashMap(16));

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 1.从单例对象缓存中获取beanName对应的单例对象
        Object singletOnObject= this.singletonObjects.get(beanName);
        // 2.如果单例对象缓存中没有,并且该beanName对应的单例bean正在创建中
        if (singletOnObject== null && isSingletonCurrentlyInCreation(beanName)) {
            //尝试给一级缓存对象加锁,因为接下来就要对缓存对象操作了
            synchronized (this.singletonObjects) {
                // 4.从早期单例对象缓存中获取单例对象(之所称成为早期单例对象,是因为earlySingletonObjects里
                // 的对象的都是通过提前曝光的ObjectFactory创建出来的,还未进行属性填充等操作)
                //尝试从二级缓存earlySingletonObjects这个存储还没进行属性添加操作的Bean实例缓存中获取
                singletOnObject= this.earlySingletonObjects.get(beanName);
                // 5.如果在早期单例对象缓存中也没有,并且允许创建早期单例对象引用
                //如果还没有获取到并且第二个参数为true,为true则表示bean允许被循环引用
                if (singletOnObject== null && allowEarlyReference) {
                    // 6.从单例工厂缓存中获取beanName的单例工厂
                    //从三级缓存singletonFactories这个ObjectFactory实例的缓存里尝试获取创建此Bean的单例工厂实例
                    ObjectFactory> singletOnFactory= this.singletonFactories.get(beanName);
                    //如果获取到工厂实例
                    if (singletonFactory != null) {
                        // 7.如果存在单例对象工厂,则通过工厂创建一个单例对象
                        singletOnObject= singletonFactory.getObject();
                        // 8.将通过单例对象工厂创建的单例对象,放到早期单例对象缓存中
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        // 9.移除该beanName对应的单例对象工厂,因为该单例工厂已经创建了一个实例对象,并且放到earlySingletonObjects缓存了,
                        // 因此,后续获取beanName的单例对象,可以通过earlySingletonObjects缓存拿到,不需要在用到该单例工厂
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        // 10.返回单例对象
        return singletonObject;
    }
}
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        if (logger.isTraceEnabled()) {
            logger.trace("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        //判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载。
        Class> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            // 如果resolvedClass存在,并且mdb的beanClass类型不是Class,并且mdb的beanClass不为空(则代表beanClass存的是Class的name),
            // 则使用mdb深拷贝一个新的RootBeanDefinition副本,并且将解析的Class赋值给拷贝的RootBeanDefinition副本的beanClass属性,
            // 该拷贝副本取代mdb用于后续的操作
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            // 2.验证及准备覆盖的方法(对override属性进行标记及验证)
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            // 3.实例化前的处理,给InstantiationAwareBeanPostProcessor一个机会返回代理对象来替代真正的bean实例,达到“短路”效果
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            // 4.如果bean不为空,则会跳过Spring默认的实例化过程,直接使用返回的bean
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
            // 5.创建Bean实例(真正创建Bean的方法)
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            // 6.返回创建的Bean实例
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            // A previously detected exception with proper bean creation context already,
            // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }
}

3、AbstractAutowireCapableBeanFactory.createBean方法触发doCreateBean依次调用以下方法实现bean创建过程:

  • A、createBeanInstance: 实例化bean, 如果需要依赖其他对象则首先创建其他对象(发生循环依赖的地方)
  • B、addSingletonFactory: 将实例化bean加入三级缓存
  • C、populateBean: 初始化bean, 如果需要依赖其他对象则首先创建其他对象(发生循环依赖的地方)
  • D、initializeBean
  • E、registerDisposableBeanIfNecessary
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory {

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        // 1.新建Bean包装类
        BeanWrapper instanceWrapper = null;
        //如果RootBeanDefinition是单例的,则移除未完成的FactoryBean实例的缓存
        if (mbd.isSingleton()) {
            // 2.如果是FactoryBean,则需要先移除未完成的FactoryBean实例的缓存
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            // 3.根据beanName、mbd、args,使用对应的策略创建Bean实例,并返回包装类BeanWrapper
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        // 4.拿到创建好的Bean实例
        final Object bean = instanceWrapper.getWrappedInstance();
        // 5.拿到Bean实例的类型
        Class> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    // 6.应用后置处理器MergedBeanDefinitionPostProcessor,允许修改MergedBeanDefinition,
                    // Autowired注解、Value注解正是通过此方法实现注入类型的预解析
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        // 7.判断是否需要提早曝光实例:单例 && 允许循环依赖 && 当前bean正在创建中
        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");
            }
            // 8.提前曝光beanName的ObjectFactory,用于解决循环引用
            // 8.1 应用后置处理器SmartInstantiationAwareBeanPostProcessor,允许返回指定bean的早期引用,若没有则直接返回bean
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        // 初始化bean实例。
        Object exposedObject = bean;
        try {
            // 9.对bean进行属性填充;其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的bean实例
            populateBean(beanName, mbd, instanceWrapper);
            // 10.对bean进行初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            // 11.如果允许提前曝光实例,则进行循环依赖检查
            Object earlySingletOnReference= getSingleton(beanName, false);
            // 11.1 earlySingletonReference只有在当前解析的bean存在循环依赖的情况下才会不为空
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    // 11.2 如果exposedObject没有在initializeBean方法中被增强,则不影响之前的循环引用
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    // 11.3 如果exposedObject在initializeBean方法中被增强 && 不允许在循环引用的情况下使用注入原始bean实例
                    // && 当前bean有被其他bean依赖
                    // 11.4 拿到依赖当前bean的所有bean的beanName数组
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set actualDependentBeans = new LinkedHashSet(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        // 11.5 尝试移除这些bean的实例,因为这些bean依赖的bean已经被增强了,他们依赖的bean相当于脏数据
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            // 11.6 移除失败的添加到 actualDependentBeans
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        // 11.7 如果存在移除失败的,则抛出异常,因为存在bean依赖了“脏数据”
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            // 12.注册用于销毁的bean,执行销毁操作的有三种:自定义destroy方法、DisposableBean接口、DestructionAwareBeanPostProcessor
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }
        // 13.完成创建并返回
        return exposedObject;
    }
}

主要的步骤为:

  • 1、Bean A的首次创建,会调用doCreateBean方法,在doCreateBean方法里会经过层层包装,在调用createBeanInstance方法之后,会创建一个没有任何属性的Bean的实例,并返回该实例的包装类BeanWrapper。

  • 2、在调用addSingletonFactory方法之前,将Bean A实例放入ObjectFactory里面,然后调用addSingletonFactory方法将Bean A相关的ObjectFactory实例添加到三级缓存singletonFactories中,此时只有三级缓存中保存了该Bean 对应的ObjectFactory实例。

  • 3、随后调用populateBean方法给属性赋值,由于Bean A直接依赖于Bean B,所以在populateBean方法中会再次调用getBean方法在容器里去尝试获取Bean B的实例。此时由于Bean B实例还没有创建出来,因此又会递归的调用到doCreateBean方法,在doCreateBean方法中调用createBeanInstance方法创建出Bean B实例,并将其对应的ObjectFactory方法放入到三级缓存中,此时三级缓存中就保存了循环依赖的Bean A和B的各自的ObjectFactory实例。

  • 4、随后在Bean B实例又会调用populateBean方法给其属性赋值。此时由于Bean B又依赖于Bean A,所以在populateBean方法中又会调用getBean方法尝试获取Bean A实例。

  • 5、此时会调用AbstractBeanFactory中的doGetBean方法,doGetBean方法会尝试调用getSingleton方法从三级缓存中去获取Bean A的实例。而在一级缓存singletonObjects和二级缓存earlySingletonObjects中都获取不到,而在三级缓存singletonFactories中获取到Bean A实例对应的ObjectFactory实例,调用其getObject方法获取Bean A实例。通过getObject方法获取到了Bean A实例之后,将A实例放入到二级缓存中,同时清空三级缓存中的实例,并将Bean A实例返回。

  • 6、由于Bean A实例实在Bean B实例执行populateBean方法的时候获取到了,此时已经将Bean A实例注入到了Bean B实例中,此时Bean B会执行完doCreateBean的剩余方法,并返回一个初始化完整的Bean实例。

  • 7、由于doCreateBean方法是通过doGetBean方法调用的,所以会将完整的Bean B实例逐层返回到doGetBean方法(AbstractBeanFactory)中。而AbstractBeanFactory的getSingleton方法在执行singletOnObject= singletonFactory.getObject()代码时,才正式执行createBean方法。

  • 8、在getSingleton方法中会最终执行addSingleton(beanName, singletonObject)方法,在addSingleton方法中会将Bean B实例添加进一级缓存singletonObjects中,并将Bean B实例从二级缓存(earlySingletonObjects)和三级缓存(singletonFactories)中清除,此时表明彻底完成了Bean B实例的创建,随后将完整的Bean B实例返回。

  • 9、Bean B实例的创建是由于Bean A实例调用populateBean方法触发的,所以此时,又会回到创建Bean A时的populateBean方法中,此时Bean A就赋值上了完整的Bean B,在Bean A实例完整创建之后又会逐层返回到doGetBean方法中,之后又会调用addSingleton将Bean A实例放入到一级缓存中,同时清除二级和三级缓存中的Bean A实例。

Spring5IOC容器解析——单例循环依赖的解决
Spring解决循环依赖

循环依赖的情况

  • 构造函数循环依赖(singleton、prototype)
  • Setter注入循环依赖(singleton、prototype)

对于prototype的Bean,Spring默认是不支持相关的循环依赖

// 4.scope为prototype的循环依赖校验:如果beanName已经正在创建Bean实例中,而此时我们又要再一次创建beanName的实例,则代表出现了循环依赖,需要抛出异常。
// 例子:如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖
if (isPrototypeCurrentlyInCreation(beanName)) {
    throw new BeanCurrentlyInCreationException(beanName);
}

单例Setter注入循环依赖(singleton)问题的解决,主要是单例的三级缓存,三级缓存除了解决循环依赖之外,还解决了保持单例唯一性的问题,因为从缓存中取出来的Bean实例是要保证唯一的,所以三级缓存支持不了prototype,因为prototype的Bean实例不唯一。

正式因为没有三级缓存的支持,才导致prototype不支持循环依赖。

构造函数循环依赖(singleton)【这个Spring解决不了】

由于单例的构造函数注入方式,实在doCreateBean方法中的createBeanInstance方法中完成的,此时还没有三级缓存。在createBeanInstance方法中的autowireConstructor(beanName, mbd, ctors, args)方法中进行Bean的实例化和参数注入,而此时构造函数的实例参数并没有构造出来,所以构造函数的参数实例也会调用getBean方法去创建实例参数,而实例参数又需要之前依赖的实例参数,最后又会递归到autowireConstructor方法,所以导致无限循环。

参考:
https://blog.nowcoder.net/n/2bb528b258b44c7eab1703a52170ef09

https://blog.csdn.net/weixin_30951389/article/details/97471000

https://www.cnblogs.com/liuqing576598117/p/11227007.html


推荐阅读
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了如何将CIM_DateTime解析为.Net DateTime,并分享了解析过程中可能遇到的问题和解决方法。通过使用DateTime.ParseExact方法和适当的格式字符串,可以成功解析CIM_DateTime字符串。同时还提供了关于WMI和字符串格式的相关信息。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
author-avatar
手机用户2502891655
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有