spring源码-之解决循环依赖

Spring如何解决循环依赖

为了解决循环依赖,Spring 使用了三级缓存。一级缓存用于存储 bean 定义。二级缓存用于存放已经创建但还没有完全初始化的前期bean实例。三级缓存用于存放完全初始化的bean实例。

当检测到循环依赖时,Spring 会创建一个部分初始化的 bean 实例并将其存储在二级缓存中。这允许 Spring 通过将部分初始化的 bean 实例注入到依赖它的另一个 bean 中来解决循环依赖。一旦解决了循环依赖,Spring 就可以完全初始化 bean 实例并将其存储在三级缓存中。

核心源码来自 Spring 框架中的 AbstractAutowireCapableBeanFactory 类。此类负责创建和初始化 bean 实例。核心部分在doCreateBean 方法种,该方法在创建新 bean 实例时调用。

以下为部分代码

/d:/study/spring-framework/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
if (instanceWrapper == null) { // Check if instanceWrapper is null
    instanceWrapper = createBeanInstance(beanName, mbd, args); // instanceWrapper if it is null
}
Object bean = instanceWrapper.getWrappedInstance(); // Get the wrapped instance from the instanceWrapper
Class<?> beanType = instanceWrapper.getWrappedClass(); // Get the wrapped class from the instanceWrapper
if (beanType != NullBean.class) { // Check if the beanType is not NullBean
    mbd.resolvedTargetType = beanType; // Set the resolvedTargetType to the beanType
}

// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) { // Synchronize on the postProcessingLock
    if (!mbd.postProcessed) { // Check if the bean definition has not been post-processed
        try {
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); // Apply post-processors to the merged bean definition
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Post-processing of merged bean definition failed", ex); // Throw a BeanCreationException if post-processing fails
        }
        mbd.postProcessed = true; // Set the postProcessed flag to true
    }
}

// 提前暴露单例对象解决循环依赖(循环依赖)
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName)); // Check if early singleton exposure is allowed
if (earlySingletonExposure) { // 如果是提前暴露了
    if (logger.isTraceEnabled()) {
        logger.trace("Eagerly caching bean '" + beanName +
                "' to allow for resolving potential circular references"); // Log a message indicating that the bean is being eagerly cached
    }
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); // 添加bean进入三级缓存
}

// 初始化实例
Object exposedObject = bean; // Set the exposedObject to the bean
try {
    populateBean(beanName, mbd, instanceWrapper); // Populate the bean with property values
    exposedObject = initializeBean(beanName, exposedObject, mbd); // Initialize the bean
}
catch (Throwable ex) { // Catch any exceptions that occur during initialization
    if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex; // If the exception is a BeanCreationException and the bean name matches, re-throw the exception
    }
    else {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); // Otherwise, throw a new BeanCreationException
    }
}
// 如果提前暴露对象,则尝试从缓存中获取。
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 " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

posted @ 2023-04-13 09:46  itqczzz  阅读(28)  评论(0编辑  收藏  举报