spring

spring循环引用

2019-10-31  本文已影响0人  loveFXX

spring在默认单例的情况下是支持循环引用的
代码体现在AbstractAutowireCapableBeanFactory#doCreateBean方法中
(boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));)
isSingleton是否是单例 ,allowCircularReferences 默认是true,可以通过api关闭循环依赖。
通过AbstractAutowireCapableBeanFactory#setAllowCircularReferences(false)方法关闭

    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        this();
        register(annotatedClasses);
        setAllowCircularReferences( false );
        refresh();
    }

循环依赖示例代码

package com.cycle;
@Component
public class A {
    @Autowired
    B b;
    int ac=5;
}

package com.cycle;
@Component
public class B {
    @Autowired
    A a;
    int bc=3;
}

debug过程

根据beanName=a,获取getBean(a)


getbean.png

调用到doGetBean(a)方法


doGetBean.png
进入getSingleton方法
getSingleton.png

首先设置此时正在创建a,放入集合。调用getObject进入lamdba表达式createBean


getObject.png
createBean调用到doCreateBean
createBean.png
创建bean
经过推断构造方法,缓存注解信息,暴露对象工厂,到属性填充
doCreateBean.png
属性填充
populateBean.png

调用后置处理器进行属性填充(模版方法)
AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues


postProcessPropertyValues.png
注入
inject.png
elementinject.png
resolveDependency.png
doResolveDependency.png
resolveCandidate.png
BeanFactorygetBean.png
getBeanB.png
所谓循环依赖,就是A含有B的属性,B含有A的属性。
从debug大概流程:getBean(beanName)说起,首先需要创建A,A需要填充属性B,注入B需要从BeanFactory(Bean工厂)查询B是否存在,现在肯定不存在则继续创建B,B需要填充属性A,再次从bean工厂查询,到这里则A能查询到。(此时将会经过spring后置处理器全部过程)
getSingletona.png
singletonFactorygetObject.png
此时,A正在创建isSingletonCurrentlyInCreation(a)返回true,将会从singletonFactories得到。得到之后放到earlySingletonObjects中,并把singletonFactories中移除,并一直返回并进行属性set 。B注入从singletonFactories查询到的A对象
getEarlyBeanReference.png
BPPgetEarlyReference.png
public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }
fieldset.png
fieldsetAfter.png

A注入B之后,经过B的生命周期,返回得到带有A属性的B对象。B注入到A之中,最终效果如下图


AfieldsetB.png
再经过A 的其他生命周期过程。完成循环依赖过程

方法参考

singletonsCurrentlyInCreation添加正在被创建bean

if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
                return createBean(beanName, mbd, args);
                }
            });
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }

添加单例工厂,提前暴露工厂

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);
            }
        }
    }

getSingleton()方法
bean:首先得是一个对象,然后这个对象需要经历一系列的bean生命周期(bean后置处理器处理过程)

   public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }
    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;
    }

AbstractAutowireCapableBeanFactory#doCreateBean源码

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

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            //第二次后置处理器 推断构造方法
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        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 {
                    //第三次后置处理器  缓存注解信息
                    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.
               //解决循环引用的地方
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            //第四次 后置处理器 暴露对象到singlentonfactories集合中 解决循环依赖问题
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            //填充属性
            //第五次 是否需要填充属性
            //第六次 填充属性
            populateBean(beanName, mbd, instanceWrapper);

            //初始化bean
            //第七次
            //第八次  aop
            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) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                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;
    }

AbstractAutoProxyCreator#getEarlyBeanReference 处理代理类

    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        this.earlyProxyReferences.put(cacheKey, bean);
        return wrapIfNecessary(bean, beanName, cacheKey);
    }

总结:

getSingleton()方法是解决循环依赖的关键。
有三个缓存集合
1、singletonObjects
bean放到里面,经历完整生命周期
2、singletonFactories
存放生成对象的工厂 是一个表达式 (包含对象) 对象需要改变,改变之后放到3
如果依赖的对象需要实现aop,则需要在这里存一个能够完成生成代理类的工厂。如果不在这里代理则注入的对象没有代理功能
参考AbstractAutoProxyCreator#getEarlyBeanReference方法
3、earlySingletonObjects
工厂生成的对象,此时生命周期没有走完。如果还有其他地方引用就不需要再通过2再次生成

关键点:
1、singletonsCurrentlyInCreation集合
当创建bean时,将首先DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory<?>)表达式中
beforeSingletonCreation(beanName)加进去
2、addSingletonFactory方法
通过方法addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));添加到singletonFactories。当再次调用时ObjectFactory的实现类AbstractAutowireCapableBeanFactory$lambda的getObject()方法最终调用getEarlyBeanReference方法,返回bean实例

上一篇下一篇

猜你喜欢

热点阅读