spring的三级缓存和循环依赖问题

循环依赖是一个老生常谈的问题,被大家所熟知。大家也都知道spring采用setter注入解决循环依赖问题。但是spring底层是怎么解决循环依赖问题的呢?

没错就是spring的三级缓存来解决循环依赖问题,今天我们就一起聊一聊spring的三级缓存,何它为什么解决循环依赖问题。

 

什么是Spring循环依赖呢?

spring的三级缓存和循环依赖问题_第1张图片

 

 

spring中Bean的生命周期是什么样子的?

想聊spring的循环依赖问题,那么我们就必须清楚的理解spring中创建Bean对象的过程,不然就是高空建楼。

  1. BeanFactory初始化  

  2. BeanDifinition加载xml、注解的创建对象所需要的配置信息(依赖注入 、属性注入过程)

  3. BeanFacctoryPostProcessor 把BeanDifinition定义配置信息修改加载到BeanFactory 

  4. BeanFactory工厂实例化Bean对象

  5. BeanFactory工厂初始化对象 (初始化分为三个步骤)

                 . BeanPostProcessor--- before

                 . init-method      ---初始化方法

                 . BeanPostProcessor  ---after

     到此为止 spring创建对象的过程我们大致的了解了一下  

 

spring创建对象的过程图解

spring的三级缓存和循环依赖问题_第2张图片

 

Spring的循环依赖问题出现在spring创建过程的那一步?

    bean对象初始化的过程(Spring的对象的创建过程拆分成实例化和初始化两个过程。实例化只是创建对象实例,而初始化是对象的属性资源进行填充赋值)

 

 

什么是Spring的三级缓存?

说了那么多废话,终于到正题了(也不算是废话,能帮助我们理解构成知识体系结构)。

 

三级缓存就是DefaultSingletonBeanRegistry类的三个hashmap

/** 一级缓存:singletonObjects:存放初始化好的bean,可以直接使用的bean*/

/** Cache of singleton objects: bean name --> bean instance */

private final Map singletonObjects = new ConcurrentHashMap(256);







/**二级缓存:经过一级缓存处理后的实例化bean,是singletonFactory 制造出来的 singleton 的缓存。*/

/** Cache of singleton factories: bean name --> ObjectFactory */

private final Map> singletonFactories = new HashMap>(16);





/**三级缓存:存放工厂  /

/** Cache of early singleton objects: bean name --> bean instance */

private final Map earlySingletonObjects = new HashMap(16);

 

常见的解决循环依赖的是setter注入,也可以采用构造器和setter方法混合使用解决循环依赖问题

循环依赖的本质解决方案是spring的DefaultSingletinBenRegistry三个map类实现的,俗称三级缓存。

 

在spring获取对象的时候 ,首先会在一级缓存中寻找bean对象,如果,没有那么就会去二级缓存找,然后三级缓存继续找,找不到就创建对象。

1.从缓存中。优先从一级缓存中拿,有则返回。 如果没有,则从二级缓存中获取,有则返回。 如果二级缓存中拿不到,则从三级缓存中拿,能拿到,则从三级缓存中删除,移到二级缓存。

如果三级缓存也没有,则返回null.

2. 如果是单例模式, 则走createBean 的流程,进行bean对象的实例化。

  2.1 获取到该beanDefinition对应的字节码对象。

2.2 prepareMethodOverrides。 检查beanDefinition对象的每一个methodOverride的对象。如果该对象对应的同名的方法只有一个则设置为false, 默认设置为true.

2.3 调用doCreateBean 方法,进行具体的实例化过程。

3.

3.1 如果是单例的,则从bean工厂的实例缓存中获取bean对象。

if (mbd.isSingleton()) {

   instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);

}

3.2 如果获取到的为空, 则进行bean对象的实例化创建。调用createBeanInstance





if (instanceWrapper == null) {

   //创建实例,,重点看,重要程度:5

   instanceWrapper = createBeanInstance(beanName, mbd, args);

}

3.3如果有FactoryMethodName属性,则通过factorymethod 方法进行对象的实例化。





if (mbd.getFactoryMethodName() != null) {

   return instantiateUsingFactoryMethod(beanName, mbd, args);

}

3.4 否则,寻找当前正在实例化的bean中有@Autowired注解的构造函数

  // 调用SmartInstantiationAwareBeanPostProcessor类型的beanpostProcess.determineCandidateConstructors 获取有autowired和value注解的构造器。





Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

3.5 //如果ctors不为空,就说明构造函数上有@Autowired注解, 则通过构造函数进行初始化。





if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||

      mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {

   //如果ctors不为空,就说明构造函数上有@Autowired注解

   return autowireConstructor(beanName, mbd, ctors, args);

}

3.6 如果首选的构造器不为空, 则使用首选的构造器进行实例化,以及进行以来注入





// Preferred constructors for default construction?

ctors = mbd.getPreferredConstructors();

if (ctors != null) {

   return autowireConstructor(beanName, mbd, ctors, null);

}

3.7 否则调用无参构造函数进行bean的实例化。





//无参构造函数的实例化,大部分的实例是采用的无参构造函数的方式实例化,并包装成一个BeanWrapper 对象进行返回。

return instantiateBean(beanName, mbd);

4. 调用applyMergedBeanDefinitionPostProcessors。主要是对实现了MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition方法调用。

  主要的实现类有:

    4.1  AutowiredAnnotationBeanPostProcessor。在postProcessMergedBeanDefinition方法中实现对Autowired,Value注解的注解信息收集,封装到externallyManagedConfigMembers。





    4.2  CommonAnnotationBeanPostProcessor。 在postProcessMergedBeanDefinition方法中实现对@PostConstrutor 和 @ PreDestory ,@Resource 注解的信息收集,封装到externallyManagedConfigMembers。

5. 检查是否允许循环依赖,以及是否是单例模式。满足条件的话,从二级缓存中移除,并且添加到三级缓存中。

6.进行属性的注入,调用populateBean 方法。

   6.1 根据注入的模式,进行对应属性的字段,filed ,以及method依赖的解析。获取其依赖的对象的值。

   6.2 调用实现了InstantiationAwareBeanPostProcessor接口的postProcessProperties 方法,对有autowired,value,resource 注解的属性实现属性值的注入。

        在AutowiredAnnotationBeanPostProcessor中实现对autowired,value 属性的注入。

        在CommonAnnotationBeanPostProcessor中实现对resource 属性的注入。

  6.3 调用applyPropertyValues 方法,实现对 标签的属性值的解析。

7.调用bean的initializeBean方法,完成bean 实例化过程的后续操作。

  7.1 调用invokeAwareMethods 方法。根据是否实现了 一系列的aware 接口,调用其对应的方法

  7.2 调用BeanPostProcessor接口的postProcessBeforeInitialization方法。进行bean初始化的前期方法调用。对 initmethod,,afterpeoperties, postcontructor 方法调用。

       1.InitDestroyAnnotationBeanPostProcessor中实现对@PostContrustor注解标识的方法进行调用









                2.调用实现了InitializingBean 接口的afterpropertiesSet 方法。

                3.调用指定了init-method属性的方法。





     7.3  调用applyBeanPostProcessorsAfterInitialization方法,实现对BeanPostProcessor的postProcessAfterInitialization的方法的调用(TODO 这一个涉及到AOP的实现。后续完善。)

  

8.调用 registerDisposableBeanIfNecessary 方法。实现spring容器销毁时,bean 对象销毁是的操作注册。

二级缓存其实就够解决循环依赖问题,但为什么还有三级缓存?

三级缓存其实在不考虑aop代理的情况下完全时够用的 ,在循环依赖问题中,如果循环对象是代理的,三级缓存的工厂可以提前暴露代理对象来解决依赖注入。如果用二级缓存的话,那么二级缓存就必须在实例化被代理对象之后立刻代理被代理对象,这样违背了spring的设计初衷 。spring的代理都在后置处理器BeanPostProcessor中完成代理的步骤,

 

 

你可能感兴趣的:(spring学习总结)