Java 开发

Spring 知识图解

言七墨 · 10月12日 · 2020年 · 1709次已读

一、Spring MVC 的工作流程

二、Bean 的生命周期

三、AO言七墨P 术语

四、SpringBoot的启动流程

五、循环依赖

Spring解决循环依赖有两个前提条件:

  • Field https://qimok.cn注入
  • 必须是单例

解决循环依赖的问题本质上就是通过三级缓存,通过三级缓存拿到未初始化的对象

// 第一级缓存:用来保存实例化、初始化都完成的对象 
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

// 第二级缓存:用来保存`实例化完成`,但是`未初始化完成`的对象
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

// 第三级缓存:用来保存`一个对象工厂`,`提供一个匿名内部类`,`用于创建二级缓存中的对象`
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

对象的创建过程

  1. 创建对象A,实例化的时候把A对象工厂放入三级缓存
  2. A属性注入的时候,发现依赖B,此时将实例化的A通过addSingletonFactory(黄色节点)方法缓存,转而去实例化B
  3. 同样创建对象B,注入属性时发现依赖A依次从一级到三级缓存查询A,从三级缓存通过对象工厂拿到A,把A放入二级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,然后把B放入一级缓存
  4. 接着继续创建A,顺利从一级缓存拿到实例化且初始化完成的B对象,A对象也创建完成,删除二级缓存中的A,同时把A放入一级缓存
  5. 最后,一级缓存中保存着实例化、初https://qimok.cn始化都完成的A、B对象

注意:由于把实例化初始化的流程分开了,所以如果都是用构造器注入的话,就没法言七墨分离这个操作,所以用构造器注入无法解决循环依赖的问题。

为什么要三级缓存?二级不行吗?

  • 不可以,主要是为了生成代理对象
  • 因为三级缓存中放的是生成具体对象的匿名内部类,它可以生成代理对象,也可以是普通的实例对象
  • 使用三级缓存主要是为了保证不管什么时候使用的都是一个对象
  • 假设只有二级缓存的情况,往二级缓存中放的先是一个普通的Bean对象BeanPostProcessor去生成代理对象之后,会覆盖掉二级缓存中的普通的Bean对象,那么https://qimok.cn多线程环境下可能取到的对象就不一致
0 条回应