SpringIOC的循环依赖解析

Posted lisin-lee-cooper

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringIOC的循环依赖解析相关的知识,希望对你有一定的参考价值。

一.示例代码及解析

循环依赖分为自身依赖于自身、互相循环依赖、多组循环依赖,代码如下所示

@Getter
@Setter
public class ClazzA {

    @Autowired
    private ClazzB b;

    @Autowired
    private ClazzA a;

}
@Setter
@Getter
public class ClazzB {

    @Autowired
    private ClazzA a;

}
public class TestIOCDependence {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
        ClazzA clazzA = applicationContext.getBean(ClazzA.class);
        System.out.println(clazzA);
        System.out.println(clazzA.getB());
    }
}

1.创建Bean的方法 doGetBean

protected <T> T doGetBean(
            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
            throws BeansException {
        // 从缓存中获取Bean 三级缓存
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            // 这里如果是普通Bean 的话,直接返回,如果是 FactoryBean 的话,返回它创建的那个实例对象
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
                // Create bean instance.
                if (mbd.isSingleton()) {
                    // 创建单例Bean
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            // 创建 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;
                        }
                    });
                    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
                
            }
        }
        // 转化Bean为真正需要的类型,有点像适配器模式
        return adaptBeanInstance(name, beanInstance, requiredType);
    }

2.核心方法 createBean 中的 doCreateBean

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

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            // 创建 bean 实例,将 bean 实例包装到 BeanWrapper 对象中返回
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
        
        // 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");
            }
            // addSingletonFactory 添加 bean 工厂对象到 singletonFactories 缓存中
            // 获取原始对象的早期引用,在 getEarlyBeanReference 方法中,会执行 AOP 相关逻辑。若 bean 未被 AOP 拦截 则原样返回 bean
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            // 填充属性 属性赋值
            populateBean(beanName, mbd, instanceWrapper);
            // 调用 实现的Aware接口和applyBeanPostProcessors 的方法  
            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);
            }
        }
        return exposedObject;
    }
	

3.getSingleton 三级缓存 ,解决循环依赖

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  // 从 singletonObjects 获取实例,singletonObjects 是成品 bean
	Object singletonObject = this.singletonObjects.get(beanName);
	// 判断 beanName ,isSingletonCurrentlyInCreation 对应的 bean 是否正在创建中
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
		  // 从 earlySingletonObjects 中获取提前曝光未成品的 bean
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
			  // 获取相应的 bean 工厂
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
				  // 提前曝光 bean 实例,主要用于解决AOP循环依赖
					singletonObject = singletonFactory.getObject();
					
					// 将 singletonObject 放入缓存中,并将 singletonFactory 从缓存中移除
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

二.为什么要使用三级缓存?

1.一级缓存能不能解决问题?

根据Spring创建Bean的流程可知当创建成品A时, 属性赋值需要注入成品B,成品B的创建又需要依赖成品A,此时A未创建,因此会出现死循环。

2.二级缓存能解决问题吗?

在创建A成品时,会在注入属性时提前暴露一个A的半成品,当注入创建B时,会将B依赖的A的半成品赋值给B,此时B成品创建完成时,A成品自然也创建完成。因此二级缓存能解决循环依赖问题。

3.三级缓存的作用是什么?

三级缓存主要是解决 Spring AOP 的特性。AOP 本身就是对方法的增强,并不是所有Bean都会执行AOP,为了统一Spring Bean的创建过程将其放到三级缓存中处理,最终获取到以后调用 getObject 方法返回代理引用或者原始引用。从而解决了 Spring AOP 带来的三级缓存问题。

Spring Bean的创建的详细过程

以上是关于SpringIOC的循环依赖解析的主要内容,如果未能解决你的问题,请参考以下文章

Spring源代码解析 ---- 循环依赖

使用循环片段依赖关系模块化单活动Android应用程序

Spring IOC BeanDefinition解析

Spring 如何解决循环依赖的问题

Spring:bean的循环依赖问题

100行代码撸完SpringIOC容器