Spring三级缓存解决循环依赖

本文深入探讨了Spring框架在处理循环依赖时遇到的问题,详细解释了AOP代理对象与普通对象的区别,以及Spring如何通过三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)来解决循环依赖。在创建Bean的过程中,Spring首先尝试从一级缓存获取,如果没有则检查二级缓存,最后从三级缓存创建并放入二级缓存。当存在多个依赖于同一Bean的场景时,Spring依然能保证单例的正确性。

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

什么叫循环依赖?

@Component
public class CircularDependencyA {

    private CircularDependencyB circB;
    
    @Autowired
    public CircularDependencyA(CircularDependencyB circB) {
        this.circB = circB;
    }
}

@Component
public class CircularDependencyB {
    private CircularDependencyA circA;

    @Autowired
    public CircularDependencyB(CircularDependencyA circA) {
        this.circA = circA;
    }
}

Spring初始化时会实例化Bean A 依赖B ,B依赖A,Spring启动失败:
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name ‘***’: Bean with name ‘***’ has been injected into other beans [***, ***]in its raw version as part of a circular reference

首先,我们分析A的创建过程
1、实例化
2、填充B
3、填充其他属性
4、其他步骤(AOP)
5、加入单例池
其中第二步,填充B的时候先去单例池中找,没有找到,然后会创建B,实例化B的时候,又因为依赖了A,去创建A。所以就会出现循环依赖的问题。

那么,如何打破循环依赖呢?
我们可以在实例化A时候,将它放在一个Map<‘A’,A的对象>对象中,在创建B的时候直接从Map中获取就可以了。

会不会有问题呢?
如果A需要AOP代理的时候,加入单例池的需要是A的代理对象,而我们创建B的时候引用的是A创建以后的普通对象。

为了解决这个问题,我们就需要在B创建的时候,就把AOP的代理对象放到Map中,当然,只有在循环依赖的时候才需要这样做。那么如何判断自己是否被依赖呢?
我们在实例化之前加一个步骤
0、add creatingSet<‘A’> (我们准备一个set,实例化之前我们把创建的Bean的名字放到这个set当中)
1、实例化
2、填充B
2.1、实例化
2.2、填充A -》 creatingSet<‘A’> -》AOP代理对象-》加入单例池?
2.3、填充其他属性
2.4、其他步骤
2.5、加入单例池
3、填充其他属性
4、其他步骤(AOP)
5、加入单例池
6、remove creatingSet<‘A’>
我们可以在第二步加入单例池吗?
答案是不可以的,因为单例池是存放走完完整流程的。

现在是只有B依赖A,如果还有一个C也依赖A的情况下呢?

@Component
public class CircularDependencyA {
	@Autowired
    private CircularDependencyB circB;
	@Autowired
	private CircularDependencyC circC;
}
@Component
public class CircularDependencyC {
    private CircularDependencyA circA;

    @Autowired
    public CircularDependencyC(CircularDependencyA circA) {
        this.circA = circA;
    }
}

C的创建过程和B是一样的,还会创建一个A的代理对象,这就不是单例的了,我们可以在创建了A的代理对象之后把A的代理对象放在一个Map<‘A’,A的代理对象>中,这就是二级缓存

但是在创建A的代理对象的时候我们需要用A的普通对象,并且并不是所有的对象都需要进行AOP,所以还需要一个三级缓存用来存放A的普通对象

接下来我们看源码

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
        //第1级缓存 用于存放 已经属性赋值、完成初始化的 单列BEAN
        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
        //第2级缓存 用于存在已经实例化,还未做代理属性赋值操作的 单例BEAN
        private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
        //第3级缓存 存储创建单例BEAN的工厂
        private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
        //已经注册的单例池里的beanName
        private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
        //正在创建中的beanName集合
        private final Set<String> singletonsCurrentlyInCreation =
                Collections.newSetFromMap(new ConcurrentHashMap<>(16));
        //缓存查找bean  如果第1级缓存没有,那么从第2级缓存获取。如果第2级缓存也没有,那么从第3级缓存创建,并放入第2级缓存。
        protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            Object singletonObject = this.singletonObjects.get(beanName); //第1级
            if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
                synchronized (this.singletonObjects) {
                    singletonObject = this.earlySingletonObjects.get(beanName); //第2级
                    if (singletonObject == null && allowEarlyReference) {
                        //第3级缓存  在doCreateBean中创建了bean的实例后,封装ObjectFactory放入缓存的bean实例
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            //创建未赋值的bean
                            singletonObject = singletonFactory.getObject();
                            //放入到第2级缓存
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            //从第3级缓存删除
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
            return singletonObject;
        }   
    }
    
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    
    if (instanceWrapper == null) {
        //实例化对象
        instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    }
 
    final Object bean = instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null;
    Class<?> beanType = instanceWrapper != null ? instanceWrapper.getWrappedClass() : null;
   
    //判断是否允许提前暴露对象,如果允许,则直接添加一个 ObjectFactory 到第3级缓存
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        //添加到第3级缓存
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
 
    //填充属性
    this.populateBean(beanName, mbd, instanceWrapper);
    //执行初始化方法,并创建代理
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    return exposedObject;
}

加入一级缓存

     protected void addSingleton(String beanName, Object singletonObject) {
            synchronized (this.singletonObjects) {
                // 放入第1级缓存
                this.singletonObjects.put(beanName, singletonObject);
                // 从第3级缓存删除
                this.singletonFactories.remove(beanName);
                // 从第2级缓存删除
                this.earlySingletonObjects.remove(beanName);
                // 放入已注册的单例池里
                this.registeredSingletons.add(beanName);
            }
        }
  

加入三级缓存

     protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
         synchronized (this.singletonObjects) {
             // 若第1级缓存没有bean实例
             if (!this.singletonObjects.containsKey(beanName)) {
                 // 放入第3级缓存
                 this.singletonFactories.put(beanName, singletonFactory);
                 // 从第2级缓存删除,确保第2级缓存没有该bean
                 this.earlySingletonObjects.remove(beanName);
                 // 放入已注册的单例池里
                 this.registeredSingletons.add(beanName);
             }
         }
     }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值