天天看点

Spring 三级缓存

实现类:DefaultSingletonBeanRegistry

代码入口:AbstractBeanFactory#doGetBean

// 第一级 存放着经历了完整生命周期的bean
/** Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    // 第三级 ObjectFactory 函数式接口,用于创建bean
	/** Cache of singleton factories: bean name to ObjectFactory. */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    //第二级 存储着早期爆露的bean,Bean的生命周期未结束
	/** Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
           

spring 在创建 bean 之前,会将当前正在创建的 bean 名称放在一个列表中,这个列表我们就叫做 singletonsCurrentlyInCreation,用来记录正在创建中的 bean 名称列表,创建完毕之后,会将其从 singletonsCurrentlyInCreation 列表中移除,并且会将创建好的 bean 放到另外一个单例列表中,这个列表叫做 singletonObjects

判断循环依赖的源码在下面这个位置,singletonsCurrentlyInCreation是 Set 类型的,Set 的 add 方法返回 false,说明被 add 的元素在 Set 中已经存在了,然后会抛出循环依赖的异常

三级缓存解决循环依赖

AB循环依赖问题,只有A的注入方式是set,且是Singleton,就不会出现循环依赖问题

大致过程

关注四大方法 getSingleton() doCreateBean() populateBean() addSingleton()

  1. 调用doGetBean 方法获取beanA,getSingleton(beanName) 通过bean name在一级缓存中查找,查到返回,无则继续
  2. getSingleton(String beanName, ObjectFactory<?> singletonFactory),加入创建队列,调用createBean() 方法,从创建队列删除,加入一级缓存
  3. createBean()→doCreateBean(),如果单例、支持循环依赖、是否在创建队列中,都为true → 加入三级缓存[addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));]
  4. 进行属性填充,populateBean() ,发现依赖B,进行doGetBean(),发现缓存没有,创建,然后填充属性,调用getSingleton() 从三级缓存获取工厂,执行获取到A,于是B 顺利完成初始化,并将A 升级到 二级缓存
  5. 随后 beanA 继续它的 属性填充,此时也获得了B,beanA 也完成了 createBean() 创建,回到getSingleton()方法,继续执行,从创建队列删除,加入一级缓存