深入理解Spring循环依赖----删除三级缓存,二级缓存可不可以放代理对象和普通对象?

本文深入探讨Spring框架如何解决循环依赖问题,通过三级缓存机制确保单例bean的正确初始化,避免死循环。详细分析了AbstractBeanFactory、DefaultListableBeanFactory等核心组件的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

深入理解Spring循环依赖----删除三级缓存,二级缓存可不可以放代理对象和普通对象?

Spring如何解决循环依赖

循环依赖的过程

当有循环依赖时,AB之间相互依赖,A 对象 已经实例化,并未初始化,在进行填充属性之前,将bean工厂对象放入到三级缓存之中,当进行初始化填充属性时,又对B进行实例化,此时b对象也是未被初始化,在进行填充属性之前,将bean工厂对象放入到三级缓存之中,当进行初始化属性填充时,发现B对象中有A作为其属性,那么又对A进行初始化,此时逻辑将进入这个代码块。
此时返回实例化但未被初始化的A对象(A对象中的B属性仍然没有值),将这个A对象注入到B对象的A属性中,此时B对象已经实例化并且也已经初始化成功了,此时把B对象放入到一级缓存当中,并且删除二级缓存和三级缓存有关B对象的东西, 此时有又将B对象注入到A对象的B属性中。此时把A对象放入到一级缓存中,,并且删除二级缓存和三级缓存有关A对象的东西,完成循环依赖的注入。

测试代码

首先书写最简单的代码 创建两个相互依赖的对象

package com.test.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class Student {
	@Autowired
	private Person person;

	public Person getPerson() {
		return person;
	}
}
package com.test.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class Person {
	@Autowired
	private Student student;

	public Student getStudent() {
		return student;
	}
}


package com.test;

import com.test.config.AppConfig;
import com.test.service.Person;
import com.test.service.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new AnnotationConfigApplicationContext(AppConfig.class);
        Person person=applicationContext.getBean(Person.class);
        System.out.println(person);
        System.out.println(person.getStudent());
        Student student=applicationContext.getBean(Student.class);
        System.out.println(student);
    }
}

看到源代码中 AbstractApplicationContext 抽象类中的 finishBeanFactoryInitialization

源代码中的注释 Instantiate all remaining (non-lazy-init) singletons.

实例化非懒加载的单例对象

所以疑问?对于有循环引用的对象他是怎么初始化的呢?怎么解决死循环这个问题呢?是如何保证单例的呢?接着往下看

看到 finishBeanFactoryInitializationbeanFactory.preInstantiateSingletons();

这一行是看到 这个才是真正对非懒加载的单例对象进行实例化。

紧接着我们将关注到这个方法 是DefaultListableBeanFactory 来实现的。

着重看到getBean 方法.

以下是getBean的具体实现的重要细节。

// Eagerly check singleton cache for manually registered singletons.
// 对于手动注册的单例bean ,进行循环依赖的校验
Object sharedInstance = getSingleton(beanName);

紧接着我们看到其实现

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //从一级缓存当中获取bean对象
    Object singletonObject = this.singletonObjects.get(beanName);
    //如果一级缓存中没有,并且 单例对象正在创建当中
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            //从二级缓存当中拿出bean对象
            singletonObject = this.earlySingletonObjects.get(beanName);
            //如果bean对象没拿到并且是允许循环依赖的
            if (singletonObject == null && allowEarlyReference) {
                //那么就从三级缓存当中获取bean工厂对象,这里为什么是工厂对象呢?稍后进行阐述  
                //这个三级缓存什么时候有数据呢?当一个bean对象已经实例化但是未被初始化时,就是将这个半成品bean对象的Bean工厂对象放入到三级缓存当中
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    //二级缓存用来存放 三级缓存bean工厂创建的已经被实例化,但未被初始化的bean对象
                    //二级缓存的场景是什么样子的呢?
                    //循环依赖的过程  S
                    //当有循环依赖时,AB之间相互依赖,A 对象 已经实例化,并未初始化,在进行填充属性之前,将bean工厂对象放入到三级缓存之中,当进行初始化填充属性时,又对B进行实例化,此时b对象也是未被初始化,在进行填充属性之前,将bean工厂对象放入到三级缓存之中,当进行初始化属性填充时,发现B对象中有A作为其属性,那么又对A进行初始化,此时逻辑将进入这个代码块。
                    //此时返回实例化但未被初始化的A对象(A对象中的B属性仍然没有值),将这个A对象注入到B对象的A属性中,此时B对象已经实例化并且也已经初始化成功了,此时把B对象放入到一级缓存当中,并且删除二级缓存和三级缓存有关B对象的东西, 此时有又将B对象注入到A对象的B属性中。此时把A对象放入到一级缓存中,,并且删除二级缓存和三级缓存有关A对象的东西.
                    //完成循环依赖的注入。
                    //循环依赖的过程  E
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

紧接着我们看到这个,看getSingleton实现

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

getSingleton实现 简要

//开始单例对象的创建 将bean对象标记为正在创建中...
beforeSingletonCreation(beanName);
try {
    //调用创建bean对象
    singletonObject = singletonFactory.getObject();
    newSingleton = true;
}
//删除正在创建bean对象的标记
afterSingletonCreation(beanName);
//将创建好的bean对象放入到一级缓存中,并且删除二级和三级缓存中的有关bean对象的值
if (newSingleton) {
    addSingleton(beanName, singletonObject);
}

紧接着我们看到创建bean对象的实现 createBean的实现doCreateBean

synchronized (mbd.postProcessingLock) {
    if (!mbd.postProcessed) {
        try {
            //可以继承MergedBeanDefinitionPostProcessor动态修改BeanDefinition
            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.isTraceEnabled()) {
        logger.trace("Eagerly caching bean '" + beanName +
                     "' to allow for resolving potential circular references");
    }
    //将() -> getEarlyBeanReference(beanName, mbd, bean) 这个Bean工厂对象放入到三级缓存当中,并且删除二级缓存中的有关bean  并且bean工厂创建对象时 对于一些继承了SmartInstantiationAwareBeanPostProcessor的子类进行调用,对bean对象进行更改。
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
//初始化bean对象
// Initialize the bean instance.
Object exposedObject = bean;
try {
    //填充bean对象的属性
    populateBean(beanName, mbd, instanceWrapper);
    //初始化bean对象自定义初始化逻辑
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}

紧接着对populateBean 重要细节进行详解

//是否有感知bean的初始化的类
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
    if (pvs == null) {
        pvs = mbd.getPropertyValues();
    }
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        //有两个及其重要的对于填充属性的类
        //AutoWiredAnnotationBeanPostProcessor 当使用@AutoWired注解时起作用
        //CommonAnnotationBeanPostProcessor 当使用@Resource注解时起作用
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                if (filteredPds == null) {
                    filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                }
                //这个方法 如果属性是对象属性最终调用还是 会调用BeanFactory,getBean()方法,重新走一遍现在的整个逻辑。
                pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    return;
                }
            }
            pvs = pvsToUse;
        }
    }
}

流程图

image-20210318143304536

image-20210318143405439

思考:为什么一定要使用3个缓存呢?

三级缓存是否可以去掉?二个缓存能不能实现?

  1. 首先我们要搞清楚 一级,二级,三级缓存是干什么的
  • 1级缓存 存储的是实例化,并且初始化后的 完整的bean对象
  • 2级缓存 存储的是 循环依赖中的已经实例化但未被初始化(正在创建中的)的对象,并且二级缓存中的对象时三级缓存中的bean对象工厂生产的对象。
  • 3级缓存 存储的是 循环依赖中的已经实例化但未被初始化的(正在创建中的)的对象的工厂

设想去除三级缓存,会发生什么?如果没了第三级缓存 将会影响这几段重要代码

//刚开始这段  AbstractBeanFactory.getSingleton  S
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;
//刚开始这段 getSingleton  E

//当循环依赖时  DefaultSingletonBeanRegistry.addSingletonFactory  S  
synchronized (this.singletonObjects) {
    if (!this.singletonObjects.containsKey(beanName)) {
        this.singletonFactories.put(beanName, singletonFactory);
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}
//当循环依赖时  E

将改成

//刚开始这段  AbstractBeanFactory.getSingleton  S
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    synchronized (this.singletonObjects) {
        singletonObject = this.earlySingletonObjects.get(beanName);
    }
}
return singletonObject;
//刚开始这段 getSingleton  E

//当循环依赖时  DefaultSingletonBeanRegistry.addSingletonFactory  S  
synchronized (this.singletonObjects) {
    if (!this.singletonObjects.containsKey(beanName)) {
        Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
        this.earlySingletonObjects.put(beanName, exposedObject);
        this.registeredSingletons.add(beanName);
    }
}
//当循环依赖时  E

依据上面的流程,两个缓存是可以满足循环依赖的需求的

所以综上所诉 是可以进行 两个缓存是可以满足循环依赖的。那为什么spring需要有第三级缓存呢?

看第三级缓存存的是bean对象的Bean工厂,二级缓存中的对象是通过三级缓存中bean工厂对象生产出来的bean

三级缓存存的是bean工厂,可以很好的与Bean的生产很好的解耦,如果你想要的什么样的bean,可以对这个ObjectFactory进行扩展,并且Spring这种函数式编程的实现更优雅。

总结

Spring通过使用多个缓存,来解决Spring的循环依赖,别且两个缓存也是可以解决循环依赖的,但是通过三级缓存有两个好处

  1. 第一可以很好地与构建bean对象进行解耦,当你想要创建任何的Bean对象通过继承ObjectFactory ,然后直接将继承后的对象放入到addSingletonFactory的形参中,可以做到快速替换。
  2. 使用函数式编码更优雅,更方便。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大鸟-0101

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值