Spring循环依赖及三级缓存源码解析

本文基于 SpringBoot5.1.8.RELEASE 版本源码解析

Spring IOC源码解析(1)
Spring IOC源码解析(2)
Spring拓展点及调用顺序总结

1. 图例解释说明

1. 循环依赖流程图
  1. 说明1:我们从“开始创建bean”开始查看此图,先沿着蓝色线条查看全图,蓝色线条表示的是单例模式的处理方式
  2. 说明2:旁边的缓存图,表示但是存放缓存的情况。
  3. 说明3:虚线表示获取到bean,直接返回;灰色框表示正常无循环依赖情况不会流入的流程。
  4. 说明4:流程框中的序号1.1,1.2,1.3对应文中源码的序号,表示同一个方法体内的操作,可以对照源码阅读理解。

在这里插入图片描述

2. 举例说明上图
 背景:都是单例bean。假如bean A 依赖 B;B依赖A。
  1. 先创建A:第一次创建A;A在1.1中的缓存都找不到,所有缓存都是空。
  2. 实例化A:实例化A完成;1.3中把A放入了三级缓存。
  3. 初始化A:属性赋值,发现A依赖了B;沿图中红线,查找创建B。
  4. 创建B:第一次创建B;B在1.1中的缓存找不到,所有缓存B都是空。
  5. 实例化B:实例化B完成;1.3中把B放入三级缓存。
  6. 初始化B:属性赋值,发现B依赖了A;沿着图中红线,查找A。
  7. A在三级缓存中已经存在;1.1.3.1 把A放入到二级缓存,并把A从三级缓存中删除,返回A。
  8. 初始化B中获取到A之后,把A注入到B的依赖属性中。
  9. 初始化B完成:1.2.2,1.2.3 把B放入到一级缓存,并把B从三级缓存中删除,返回B。
  10. 初始化A中获取到B,把B注入到A的依赖属性中。
  11. 初始化A完成:1.2.2,1.2.3 把B放入到一级缓存,并把A从三级缓存中删除,返回A。

2. 源码解析

我们前面进行Spring IOC的源码解析,现在我们就直接看看创建Bean的过程中,循环依赖相关的代码。

1. AbstractBeanFactory.doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                          @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
	//省略代码...

    // 获取Bean,如果该Bean存在于缓存中,就返回;如果不存在,返回null(重点关注一下) 
    Object sharedInstance = getSingleton(beanName);

    //省略代码...
    
            // Create bean instance.创建bean实例(重点关注一下)
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
			//如果是原型模式,则没取缓存,直接创建新的bean
            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                    prototypeInstance = createBean(beanName, mbd, args);
            }
            else {

            }
    //省略代码...
 
    return (T) bean;
}
1.1 getSingleton(beanName) (DefaultSingletonBeanRegistry)(这个我们重点关注)

​ 我们首先重点看看DefaultSingletonBeanRegistry中的几个属性,表达什么含义;再看看getSingleton方法。

/** Cache of singleton objects: bean name to bean instance. 一级缓存,<beanname, beanInstance>,此处的bean已经完成属性注入*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of early singleton objects: bean name to bean instance.二级缓存,<beanname, beanInstance>,此处bean已经创建,但没有注入属性*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** Cache of singleton factories: bean name to ObjectFactory. 三级缓存,<beanname, beanFactory>,beanFactory中的bean已经实例化,没有填充属性*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Set of registered singletons, containing the bean names in registration order. 注册的bean,按顺序保存*/
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

/** Names of beans that are currently in creation. 正在创建的Bean*/
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //从一级缓存中找
    Object singletonObject = this.singletonObjects.get(beanName);
    //从一级缓存没有找到已经初始化的Bean,且该Bean目前正在创建(也就是说一级缓存找到了Bean直接返回,或者该bean没有初始化且目前不在创建)
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            //从二级缓存中获取Bean
            singletonObject = this.earlySingletonObjects.get(beanName);
            //二级缓存中没有找到已经创建的Bean,且allowEarlyReference=true(是否允许从三级缓存获取Bean)
            if (singletonObject == null && allowEarlyReference) {
                //从三级缓存中获取bean工厂
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    //通过Bean工厂创建bean,然后把bean放入到二级缓存,并且从三级缓存中移除
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}
1.2 DefaultSingletonBeanRegistry.getSingleton
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {

   synchronized (this.singletonObjects) {
       //从一级缓存中拿,如果一级缓存中,存在,则直接返回,无需创建
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         if (this.singletonsCurrentlyInDestruction) {
            throw new BeanCreationNotAllowedException();
         }

          //加入到singletonsCurrentlyInCreation,表示正在创建,代码见下面
         beforeSingletonCreation(beanName);
         try {
             //通过工厂创建bean,(函数式编程,就是调用外面的createBean方法)
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         finally {
			创建bean完成,把beanname从singletonsCurrentlyInCreation移除,代码如下
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
             //创建完bean,操作缓存,代码如下
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

protected void beforeSingletonCreation(String beanName) {
    //把当前beanname加入到singletonsCurrentlyInCreation,表示正在创建
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}

protected void afterSingletonCreation(String beanName) {
    //创建bean完成,把beanname从singletonsCurrentlyInCreation移除
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
        throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
    }
}

protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        //添加到一级缓存
        this.singletonObjects.put(beanName, singletonObject);
        //从三级缓存删除
        this.singletonFactories.remove(beanName);
        //从二级缓存删除
        this.earlySingletonObjects.remove(beanName);
        //注册bean完成
        this.registeredSingletons.add(beanName);
    }
}
1.3 我们再看看创建Bean的过程: AbstractAutowireCapableBeanFactory.doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    throws BeanCreationException {

	//省略代码 ...

    //是否单例  && 是否允许循环引用 && 是否正常创建Bean
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                      isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        // 如果是,则把beanName对应的工厂放入到三级缓存,而工厂中的bean已经实例化了,但没有初始化。
        // 把此处的函数式表达式作为工厂操作方法以便后续调用;
        // 移除二级缓存;我们看看里面代码(见下面)
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    //上述已经实例化的bean,下面代码循环引用判断有用
    Object exposedObject = bean;
    try {
        populateBean(beanName, mbd, instanceWrapper);
        //初始化回调之后,bean改变了,exposedObject重新赋值
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }

	//和上面的值相同
    if (earlySingletonExposure) {
        //获取二级缓存中的bean,我们看看下面代码,注意此处的false。此处一般返回的是false,因为上面没有放入二级缓存。
        //但是如果有其他地方获取了该bean,回到1.1,就会把bean放入到二级缓存,此时二级缓存bean就存在了
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            //如果二级缓存中的bean,和初始化完成的bean一致,没有发生改变。
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            //是否允许上面放入三级缓存的bean和初始化的bean不一致 (默认是false);如果不一致抛异常
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                if (!actualDependentBeans.isEmpty()) {
                    throw new BeanCurrentlyInCreationException();
                }
            }
        }
    }

    return exposedObject;
}

DefaultSingletonBeanRegistry

//此次singletonFactory的参数: getEarlyBeanReference(beanName, mbd, bean),bean是已经实例化了
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   synchronized (this.singletonObjects) {
      if (!this.singletonObjects.containsKey(beanName)) {
      	//添加到三级缓存
         this.singletonFactories.put(beanName, singletonFactory);
         //移除二级缓存
         this.earlySingletonObjects.remove(beanName);
         this.registeredSingletons.add(beanName);
      }
   }
}

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);
            //此处一定为false,因为allowEarlyReference传进来是false
            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;
}

3. 总结几个结论和问题

  1. 只有单例的bean才有缓存,才能解决循环依赖问题;原型bean或其他bean没有使用缓存,每次都是创建新的bean。

  2. 如果依赖构造函数循环依赖,会报错;因为我们缓存是缓存的实例化完成的bean,没有实例化成功的无法缓存。

  3. 使用懒加载方式可以解决循环依赖,因为IOC容器启动时,懒加载的bean不会实例化。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值