理论基础

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

Java值传递与引用传递

Bean实例化和初始化

Bean创建流程

Spring IOC容器的三级缓存

//DefaultSingletonBeanRegistry.class

    /** 一级缓存,保存已经创建Bean,可以直接使用*/
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** 二级缓存,保存已实例化(执行了构造方法)但尚未注入属性的Bean*/
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    /** 三级缓存,保存ObjectFactory<?>,解决动态代理创建Bean可能导致Bean不唯一问题 */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** 当前正在创建Bean集合,Bean开始创建前放入,完成创建后移除 */
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

ObjectFactory

// 函数式接口,支持Lambda表达式,它可以将创建对象的步骤封装到ObjectFactory中交给自定义的Scope来选择是否需要创建对象来灵活的实现scope。具体参见Scope接口
@FunctionalInterface
public interface ObjectFactory<T> {
    T getObject() throws BeansException;
}

样例分析

假设当前Spring应用中存在两个Service类互相依赖且应用启懂事首先创建ServiceA实例

public class ServiceA {
    @Autowired
    private ServiceB serviceB;

    ...
}

public class ServiceB {
    @Autowired
    private ServiceA serviceA;

    ...
}

源码分析

Bean创建主流程为AbstractBeanFactory.class的doGetBean方法,这里主要分析单例且为非懒加载(non-lazy)加载Bean的创建过程

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

        final String beanName = transformedBeanName(name);
        Object bean;

        // 步骤1:尝试从1级缓存获取Bean实例(针对手动注册到容器中Bean)
        // Eagerly check singleton cache for manually registered singletons.
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            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 + "'");
                }
            }
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
                // 此处代码省略...

            try {
                    // 获取Bean定义
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
            
                    // 此处代码省略...
                    
                
                // 步骤2:Bean实例创建
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            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);
                }
                
                        // 此处代码省略...
                        
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // 此处代码省略...
        
        return (T) bean;
    }

分支流程步骤1处getSingleton方法如下,ServiceA实例未创建,也不存在当前正创建Bean (isSingletonCurrentlyInCreation)集合中,此处直接返回null

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 首先从1级缓存获取Bean,获取到直接返回
        Object singletonObject = this.singletonObjects.get(beanName);
        // 如果1级缓存中没有并且待获取Bean正在创建中,尝试从2级缓存获取
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                // 如果2级缓存中没有并且待获取Bean允许提前暴露引用,尝试从3级缓存获取Bean
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        // 通过getObject()拿到半成品Bean
                        singletonObject = singletonFactory.getObject();
                        // 将半成品Bean放入2级缓存
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        // 从3级缓存移除
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

步骤2处getSingleton方法

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        synchronized (this.singletonObjects) {
            // 再次尝试从1级缓存获取
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                if (this.singletonsCurrentlyInDestruction) {
                    throw new BeanCreationNotAllowedException(beanName,
                            "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                            "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
                }
                
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<>();
                }
                try {
                    // 在这里执行传入ObjectFactory方法创建Bean(即createBean方法)
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                catch (IllegalStateException ex) {
                    // Has the singleton object implicitly appeared in the meantime ->
                    // if yes, proceed with it since the exception indicates that state.
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        throw ex;
                    }
                }
                catch (BeanCreationException ex) {
                    if (recordSuppressedExceptions) {
                        for (Exception suppressedException : this.suppressedExceptions) {
                            ex.addRelatedCause(suppressedException);
                        }
                    }
                    throw ex;
                }
                finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
                    // Bean创建完成后添加至1级缓存,并从2,3级缓存中移除
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }

createBean方法会转至AbstractAutowireCapableBeanFactory.class#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()) {
            // 创建Bean对象,并且将对象包裹在BeanWrapper中
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        
        // 再从Wrapper中把Bean原始对象(非代理), 此时Bean有了地址值能被引用
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
    
        
        // ...
        
        // 是否提前暴露原始对象的引用(单例 && 允许循环依赖 && 当前正在创建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");
            }
            // 将获取当前正在创建Bean的早期引用方法添加至3级缓存
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        Object exposedObject = bean;
        try {
            // Bean属性填充
            populateBean(beanName, mbd, instanceWrapper);
            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) {
            // 此处getSingleton第二个参数为false->不会从3级缓存获取Bean
            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(...);
                    }
                }
            }
        }
        
        // ... 
        
        return exposedObject;
    }

在ServiceA属性注入时需要创建ServiceB,此时会回到AbstractBeanFactory.class的doGetBean方法进行ServiceB的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);
            }
        }
    }

@Async注解使用不当导致spring循环依赖异常问题分析

启动报错信息如下:

[ERROR] 211220 14:44:34.802 - Application run failed (org.springframework.boot.SpringApplication) (main) 
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'fqaDefectServiceImpl': Unsatisfied dependency expressed through field 'fqaReportService'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'fqaReportServiceImpl': Bean with name 'fqaReportServiceImpl' has been injected into other beans [fqaTaskInfoServiceImpl] 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.
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:370)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1336)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:548)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
    at com.tplink.tpqms.TpqmsApplication.main(TpqmsApplication.java:31)

粥于于
9 声望1 粉丝

代码搬运工


« 上一篇
Spring基础