今天看啥  ›  专栏  ›  涣涣虚心0215

Spring IOC(8)SingletonBeanRegistry与bean循环依赖的实现

涣涣虚心0215  · 简书  ·  · 2021-01-04 02:20

文章预览

DefaultListableBeanFactory继承关系

在Spring(7)里面介绍了DefaultListableBeanFactory,稍微提到了除BeanFactory之外的另外两个顶层接口BeanDefinitionRegistry和SingletonBeanRegistry。
BeanDefinitionRegistry 提供了BeanDefinition的管理功能,如下图所示:

BeanDefinitionRegistry

SingletonBeanRegistry 提供了SingletonBean的管理功能,如下图所示:

SingletonBeanRegistry

与BeanDefinitionRegistry不同的是,SingletonBeanRegistry有一个默认的实现 DefaultSingletonBeanRegistry

DefaultSingletonBeanRegistry

DefaultSingletonBeanRegistry是SingletonBeanRegistry的默认实现,所以它提供了singletonObjects来作为singleton bean的缓存,但是为了解决bean循环引用的问题,所以引入了三层缓存,即二级缓存earlySingletonObjects和三级缓存singletonFactories。

//单例bean的一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//单例bean的三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//单例bean的二级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//set类型,已注册的单例bean集合
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
//跟bean循环引用有关系,表示正在创建的单例bean集合
private final Set<String> singletonsCurrentlyInCreation =
        Collections.newSetFromMap(new ConcurrentHashMap<>(16));
//需要排除的正在创建bean的检查
private final Set<String> inCreationCheckExclusions =
        Collections.newSetFromMap(new ConcurrentHashMap<>(16));

private Set<Exception> suppressedExceptions;

//表示现在是不是destroy singleton
private boolean singletonsCurrentlyInDestruction = false;
//disposable bean的缓存
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
//
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
//dependent bean的集合
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

那么这上面的singleton的缓存是怎么解决bean的循环依赖的呢?
我们先记录下跟这三个缓存相关的方法:

//将singleton bean实例放入singletonObject一级缓存中
protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        this.singletonObjects.put(beanName, singletonObject);
        this.singletonFactories.remove(beanName);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}
//将singleton bean放入三级缓存中
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    synchronized (this.singletonObjects) {
        if (!this.singletonObjects.containsKey(beanName)) {
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}
//如果一级缓存singletonObjects存在bean,则返回。
//如果singletonObjects没有该bean,且这个bean正在创建,
//      就检查二级缓存earlySingletonObjects是否存在该bean实例。
//如果不存在就继续检查三级缓存singletonFactory,三级缓存肯定有,
//      因为这个bean正在创建中,那么就将三级缓存的值放入到二级缓存。
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;
}   

这三级缓存是怎么协同工作的?(XML版本)
Spring解决循环依赖问题是通过结合bean实例化和bean属性填装分离,singletonObjects、earlySingletonObjects 、singletonFactories 三级缓存机制和引用提前暴露机制实现的。

<bean id="teacher" class="com.gary.spring.Teacher" >
    <property name="student" ref="student"/>
</bean>
<bean id="student" class="com.gary.spring.Student" >
    <property name="teacher" ref="teacher"/>
</bean>

Student student = (Student) beanFactory.getBean("student");
System.out.println(student.getTeacher());

定义了两个bean,Teacher里面持有Student的成员变量,同时Student里面持有Teacher的引用。
当开始调用getBean("student")的时候开始创建Student的实例。
1.1)--> getBean(beanName)
开始获取Student的bean。
1.2)--> doGetBean(beanName, null, null, false)

  • 先调用 getSingleton(beanName) ,来检查三级缓存中是否存在Student bean,如果存在就直接返回了。第一次调用肯定返回null。
  • 再调用getSingleton(beanName, ObjectFactory<?> singletonFactory)
    这里面会将当前bean放入singletonsCurrentlyInCreation缓存
  • 调用createBean()创建bean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    // Eagerly check singleton cache for manually registered singletons.
    //检查三级循环
    Object sharedInstance = getSingleton(beanName);
    。。。省略代码

            // Create bean instance.
            if (mbd.isSingleton()) {
                //getSingleton(beanName, ObjectFactory<?> singletonFactory)
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        //调用createBean创建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;
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

    。。。省略代码
    return (T) bean;
}

1.3)--> doCreateBean(beanName, RootBeanDefinition, args)
这里会首先通过createBeanInstance()创建Student bean对应的实例,并且通过 addSingletonFactory(beanName, bean) 把创建的但是还未初始化的bean放入三级缓存。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {
    //创建bean的实例,封装成beanWrapper
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    //获取beanWrapper里面bean实例
    final Object bean = instanceWrapper.getWrappedInstance();
    
    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    //这里就是解决循环依赖的点
    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");
        }
        //将bean先放入三级缓存SingletonFactorys
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        //开始装载bean的相关属性值
        populateBean(beanName, mbd, instanceWrapper);
        //初始化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) {
        //如果是过早暴露singleton bean,就再检查earlySingletonObjects二级缓存
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            // allowRawInjectionDespiteWrapping 标注是否允许此Bean的原始类型被注入到其它Bean里面,即使自己最终会被包装(代理),AOP相关
            // 默认是false表示不允许,如果改为true表示允许
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    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 " +
                            "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
            }
        }
    }

    // Register bean as disposable.
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}

1.4)--> populateBean(beanName, mbd, instanceWrapper)
这个方法会populateBean的属性,然后通过applyPropertyValues()来设置property对应的属性值,

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    。。。省略部分代码
    List<PropertyValue> deepCopy = new ArrayList<>(original.size());
    boolean resolveNecessary = false;
    //主要这里开始循环遍历PropertyValueList,original = mpvs.getPropertyValueList();
    for (PropertyValue pv : original) {
        if (pv.isConverted()) {
            deepCopy.add(pv);
        }
        else {
            String propertyName = pv.getName();
            Object originalValue = pv.getValue();
            //这里需要通过valueResolver来判断并获取属性的Value
            Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
            Object convertedValue = resolvedValue;
            boolean convertible = bw.isWritableProperty(propertyName) &&
                    !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
            if (convertible) {
                convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
            }
            // Possibly store converted value in merged bean definition,
            // in order to avoid re-conversion for every created bean instance.
            if (resolvedValue == originalValue) {
                if (convertible) {
                    pv.setConvertedValue(convertedValue);
                }
                deepCopy.add(pv);
            }
            else if (convertible && originalValue instanceof TypedStringValue &&
                    !((TypedStringValue) originalValue).isDynamic() &&
                    !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                pv.setConvertedValue(convertedValue);
                deepCopy.add(pv);
            }
            else {
                resolveNecessary = true;
                deepCopy.add(new PropertyValue(pv, convertedValue));
            }
        }
    }
    if (mpvs != null && !resolveNecessary) {
        mpvs.setConverted();
    }

    // Set our (possibly massaged) deep copy.
    try {
        bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    }
    catch (BeansException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Error setting property values", ex);
    }
}   
//valueResolver根据Value的类型来获得对应的值
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
    // We must check each value to see whether it requires a runtime reference
    // to another bean to be resolved.
    if (value instanceof RuntimeBeanReference) {
        RuntimeBeanReference ref = (RuntimeBeanReference) value;
        //如果是bean的相互引用就会走这里,通过resolveReference来获得相应的值
        return resolveReference(argName, ref);
    }
    else if (value instanceof RuntimeBeanNameReference) {
        String refName = ((RuntimeBeanNameReference) value).getBeanName();
        refName = String.valueOf(doEvaluate(refName));
        if (!this.beanFactory.containsBean(refName)) {
            throw new BeanDefinitionStoreException(
                    "Invalid bean name '" + refName + "' in bean reference for " + argName);
        }
        return refName;
    }
    else if (value instanceof BeanDefinitionHolder) {
        // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
        BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
        return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
    }
    else if (value instanceof BeanDefinition) {
        // Resolve plain BeanDefinition, without contained name: use dummy name.
        BeanDefinition bd = (BeanDefinition) value;
        String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
                ObjectUtils.getIdentityHexString(bd);
        return resolveInnerBean(argName, innerBeanName, bd);
    }
    。。。省略代码
}
//resolveReference会通过this.beanFactory.getBean(refName);来获得Value的值
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
    try {
        Object bean;
        String refName = ref.getBeanName();
        refName = String.valueOf(doEvaluate(refName));
        if (ref.isToParent()) {
            if (this.beanFactory.getParentBeanFactory() == null) {
                throw new BeanCreationException(
                        this.beanDefinition.getResourceDescription(), this.beanName,
                        "Can't resolve reference to bean '" + refName +
                        "' in parent factory: no parent factory available");
            }
            bean = this.beanFactory.getParentBeanFactory().getBean(refName);
        }
        else {
            //*****这里是重点
            bean = this.beanFactory.getBean(refName);
            this.beanFactory.registerDependentBean(refName, this.beanName);
        }
        if (bean instanceof NullBean) {
            bean = null;
        }
        return bean;
    }
    catch (BeansException ex) {
        throw new BeanCreationException(
                this.beanDefinition.getResourceDescription(), this.beanName,
                "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
    }
}

看到上面的代码,在创建完Student的实例之后,开始populate Student的属性值,那么在设置Teacher的值的时候,就通过getBean(Teacher)去创建Teacher的单例bean。
那么这里开始创建Teacher相关的步骤,且与上面步骤完全一致,不同的是populateBean之后的动作

2.1)--> getBean(beanName)
开始获取Teacher的bean。
2.2)--> doGetBean(beanName, null, null, false)
2.3)--> doCreateBean(beanName, RootBeanDefinition, args)
createBeanInstance()创建Teacher的实例,并且通过addSingletonFactory(beanName, bean)把创建的但是还未初始化的bean放入三级缓存。
2.4)--> populateBean(beanName, mbd, instanceWrapper)
创建Teacher实例之后,开始populate Teacher的相关属性,这时候开始getBean(Student),获取尝试获取Student。

获取尝试获取Student,涉及到三级缓存
3.1)--> getBean(beanName)
又开始尝试获取Student的bean。
3.2)-->doGetBean(beanName, null, null, false)
这里会通过 getSingleton(beanName)来检查三级缓存 ,这个时候三级缓存中应该是由两个bean分别是Student和Teacher,那么很好, 将Student的bean从三级缓存中删除并添加到二级缓存,并且直接返回

回到2步骤继续创建Teacher
2.4)--> 又回到2.4步骤,Teacher的populateBean就能拿到Student的实例了。
2.3)--> 完成initializeBean(beanName, exposedObject, mbd)
调用初始化方法,初始化Teacher。
2.3)--> getSingleton(beanName, false)
检查earlySingletonObjects二级缓存,这里注意earlySingletonReference,思考为什么需要三级缓存而不是二级缓存?
2.2)-->getSingleton(beanName, ObjectFactory<?> singletonFactory)
方法返回,将Teacher从singletonsCurrentlyInCreation,且将Teacher从二级和三级缓存中移除,加入一级缓存singletonObjects。

回到1步骤继续创建Student
1.4)这时候回到Student Bean的1.4步骤,将Teacher值设置完成。
1.3)--> initializeBean(beanName, exposedObject, mbd)
调用初始化方法,初始化Student。
1.3)--> getSingleton(beanName, false)
检查earlySingletonObjects二级缓存
1.2)-->getSingleton(beanName, ObjectFactory<?> singletonFactory)
方法返回,将Student从singletonsCurrentlyInCreation,且将Student从二级和三级缓存中移除,加入一级缓存singletonObjects。

总结:
1)注意此文讨论的 bean为单例情况(且是set注入,而不是构造器注入) ,prototype的bean循环依赖都会抛出异常,如果是单例与prototype混合的情况,如果是先创建单例则能成功,反之则会抛出异常。
2)Spring解决循环依赖问题是通过结合bean实例化和bean属性填装分离,singletonObjects、earlySingletonObjects 、singletonFactories 三级缓存机制和引用提前暴露机制实现的。
3)上面提到的,如果是正常的bean循环引用,那么二级缓存其实也是能实现的。但是为什么要设计三级缓存呢?
使用三级而非二级缓存并非出于IOC的考虑,而是出于AOP的考虑,即若使用二级缓存,在AOP情形下,注入到其他bean的,不是最终的代理对象,而是原始对象。
相关代码就在1.3)--> doCreateBean后面earlySingletonReference。

………………………………

原文地址:访问原文地址
快照地址: 访问文章快照
总结与预览地址:访问总结与预览