Spring使用三级缓存解决Bean的循环依赖流程简括

        前面的几篇博客,更多的关注点是bean的创建过程的一些理解梳理,更多的属于基础部分,在实际开发中,业务类不大可能是单独存在,极大可能需要类之间相互引用,这就会导致循环依赖问题,循环依赖我相信大家都听过,spring也有考虑到这个问题,并给出了解决方案,就是通过使用三级缓存来处理,三级缓存,实际上就是DefaultSingletonBeanRegistry类中的三个Map集合,对应的Map集合源码如下:

//一级缓存
private final Map singletonObjects = new ConcurrentHashMap(256);

//三级缓存
private final Map> singletonFactories = new HashMap(16);

//二级缓存
private final Map earlySingletonObjects = new ConcurrentHashMap(16);

//已创建beanName集合
private final Set registeredSingletons = new LinkedHashSet(256);

//正在创建beanName集合
private final Set singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));

本篇博客中,我是对三级缓存在源码中的使用进行简要的总结概括,这样在阅读源码时,会有一个大的逻辑线路,或许理解起来更方便。处理的流程总结如下:

  • 先创建一个没有初始化属性的bean对象BeanWrapper,创建过程是doCreateBean方法中的instanceWrapper = this.createBeanInstance(beanName, mbd, args)
  • 创建完后,判断该bean是否正在创建中,校验的源码是boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
  • 判定bean正在创建后,将beanName作为key,ObjectFactory的匿名内部类的lambda表达式作为value保存在三级缓存singletonFactories的Map集合中,并标记bean已经创建,标记过程是将beanName保存在registeredSingletons的Set集合中
  • 进行bean的属性赋值操作,属性赋值的过程在populateBean方法中实现,bean对应的属性保存在RootBeanDefinition的propertyValues属性中,propertyValues属性是MutablePropertyValues对象
  • 属性对象MutablePropertyValues不为null的话,会调用applyPropertyValues()方法进行属性赋值,applyPropertyValues()方法中通过BeanDefinitionValueResolver类的resolveValueIfNecessary()方法进行逻辑处理,最终逻辑会调用该类的resolveReference()方法
  • 在resolveReference()方法中,调用resolvedName=String.valueOf(this.doEvaluate(ref.getBeanName()))方法获取需要注入的beanName,这个beanName就是刚才创建的Bean的属性中需要注入的bean的名称
  • 得到需要注入的beanName后,再次调用beanFactory的getBean()方法,getBean()方法调用doGetBean方法,属性Bean在getSingleton方法中还是取不到bean对象,将继续走bean的创建逻辑
  • 属性bean的创建调用doCreateBean方法后,也会得到一个BeanWrapper对象,并将beanName存入三级缓存中,然后走属性Bean的属性赋值逻辑,此时发现属性bean的属性需要赋值最开始创建的Bean对象,
  • 然后就需要获取最开始创建的逻辑,通过doGetBean方法中的getSingleton()方法获取
  • 此时的getSingleton()中最开始的bean正在创建过程中。并且前面讲到,这个bean已经保存到了三级缓存中了,以beanName为key,ObjectFactory为value保存。
  • getSingleton()获取bean的逻辑是,先从一级缓存中找,找不到再去二级缓存中找,再找不到就会去三级缓存中找。
  • 我们自定义的bean此之前创建过程中,都放到了三级缓存中,所以getSingleton()方法中三级缓存中是可以找到的,找到之后,执行ObjectFactory的getObject方法,getObject方法再调用createBean方法,就会得到一个最开始的bean
  • 得到Bean最开始的bean后,将bean以beanName作为key,bean对象最为value保存在二级缓存earlySingletonObjects的Map集合中,并删除对应bean在三级缓存中的信息
  • 得到最开始的bean后,将得到的这个bean对象赋值给属性bean的属性。此时属性bean已经创建完成了
  • 属性bean创建完成后,将该bean以beanName作为key,bean对象作为value,保存至一级缓存singletonObjects的Map集合中,并删除二级缓存和三级缓存中的信息
  • 再进行第一个bean的属性赋值逻辑,获取属性bean对象,这时是可以取到的
  • 然后将属性bean对象赋值到第一个bean上
  • 第一个bean创建完成后,将该bean以beanName作为key,bean对象作为value,保存至一级缓存singletonObjects的Map集合中,并删除二级缓存和三级缓存中的信息

以上就是整个spring处理循环依赖的逻辑和三级缓存的使用逻辑。逻辑比较的绕。下一篇博客再对着源码详细分解步骤记录。

你可能感兴趣的:(spring源码,spring,缓存,java)