spring框架如何解决循环依赖

什么是循环依赖

循环依赖是指一个或多个对象之间存在直接或间接的依赖关系,这种依赖关系构成一个循环。

  1. 自己依赖自己 ( eg:在A类里注入了A)
  2. 两个对象之间互相依赖(eg:A里注入了B,B里注入了A)
  3. 多个对象之间相互依赖(eg:A里注入了B,…,X里注入了A)

循环依赖的产生方式

  1. 构造器注入的循环依赖:直接抛出BeanCurrentlylnCreationException异常。
  2. 非单例循环依赖:无法处理。
  3. 单例模式下的属性注入的循环依赖:可通过三级缓存处理

spring框架无法处理构造器及非单例下的循环依赖,可以通过三级缓存处理单例模式下的循环依赖。

spring通过三级缓存处理单例模式下的循环依赖

三级缓存

首先来了解一下三级缓存:

  • 一级缓存,singletonObjects :完成了初始化的单例对象map
  • 二级缓存,earlySingletonObjects:完成实例化未初始化的单例对象ma
  • 三级缓存,singletonFactories: 单例对象工厂map,单例对象实例化完成之后会加入singletonFactories

初始化步骤

  1. createBeanInstance :实例化bean,使用构造方法创建对象,为对象分配内存。
  2. populateBean :进行依赖注入。
  3. initializeBean :初始化bean。

解决

以下引用ximeneschen的spring循环依赖及解决方法

在调用createBeanInstance进行实例化之后,会调用addSingletonFactory,将单例对象放到singletonFactories中。

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

Spring 在注入属性的时候是如何去获取依赖的呢?
他是通过一个getSingleton()方法去获取所需要的 Bean 的。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 一级缓存
    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) {
                    // Bean 工厂中获取 Bean
                    singletonObject = singletonFactory.getObject();
                    // 放入到二级缓存中
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}


当 Spring 为某个 Bean 填充属性的时候,它首先会从一级缓存中获取,一级缓存中没有就从二级缓存中获取,二级缓存中没有就从三级缓存中获取,如果三级缓存中也没有,那么就会去执行 doCreateBean() 方法创建这个 Bean。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值