Spring循环依赖和三级缓存

什么是循环依赖

在spring中我们经常使用@Autowired注解来注入依赖的bean,但是如果出现如下情况,A依赖了B,B又依赖了A我们称之为循环依赖:

@Component
public class CircleA {
    @Autowired
    private CircleB circleB;

}
@Component
public class CircleB {
    @Autowired
    private CircleA circleA;
}

循环依赖存在什么问题呢?

我们可以把spring简单理解成一个大map,key是bean的名称,value是bean的实例化对象,

  1. 当我们需要使用一个bean的时候就从这个map里面获取,
  2. 当我们新创建一个bean之后,就往这个map里面放

但是如果发生了循环依赖,实例化A的时候需要依赖B,这个时候就会去实例化B,但是这个时候B依赖了A,因为A还没实例化,所以在map里找不到A的bean,又出实例化A,这样子就进入了一个死循环,如图:

spring 是怎么解决这个问题的呢?

spring 的解决方案是通过缓存来解决的,spring定义了一个三级缓存的机制:

  • 一级缓存(singletonObject):已经实例化的对象,已经分配空间,并且执行完相关初始化方法(例如:init-method、PostProcesser),可以直接使用了
  • 二级缓存(earlySingletonObjects):提前对外暴露的对象,已经分配空间,但是还没有执行初始化方法
  • 三级缓存(singletonFactories):bean工厂,三级缓存中的对象是一个beanFactory,当我们从三级缓存中获取对象的时候,我们要从三级缓存中获取beanFactory之后调用getObject方法获取对外暴露的bean

在spring getBean的时候会先从一级缓存中获取,然后再从二级缓存中获取,最后再尝试从三级缓存获取,以下是spring的DefaultSingletonBeanRegistry#getSingleton方法的源码

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // Quick check for existing instance without full singleton lock
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            // Consistent creation of early reference within full singleton lock
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               singletonObject = this.earlySingletonObjects.get(beanName);
               if (singletonObject == null) {
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

最后来一张我觉得画的特好的一张图,该图详细说明了spring解决循环依赖的过程:

哪些对象会提前放入三级缓存中呢?

当我们进入spring 的AbstractAutowireCapableBeanFactory#createBean方法,我们可以看到有一个关于是否提前暴露的判断,符合条件的会被提前放到三级缓存:

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

   // 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(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   return exposedObject;
}

为什么要三级存储,明明两层的缓存就够了呀?

主要是为了解决AOP 代理bean的循环依赖问题,我们知道被AOP注解的bean,实际在使用的是它的代理类,但是时间创建代理类是在填充完属性之后再实现beanPostProcesser的时候创建的代理类,如果要提前创建代理类,那么就需要打破这个流程因此spring通过一个三级缓存,提前给出一个对象引用,用于依赖注入,后面再按流程进行bean的实例化。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值