spring源码学习笔记之循环依赖(十)

78 阅读3分钟

循环依赖形成的原因

先上一个图来说明一下循环依赖形成的原因:

image.png 图中是一个闭环,Spring在创建A对象的时候依赖B对象,然后去创建B对象,同时B对象也依赖A对象,导致形成循环依赖。
如果想解决这个问题,那么就必须要保证不会出现第二次创建A对象这个步骤,也就是说从容器中获取A的时候必须要能够获取到
在spring中,对象的创建可以分为实例化和初始化,实例化好还未完成初始化的对象是可以直接给其他对象引用的,所以此时可以做一件事,把完成实例化还未完成初始化的对象提前暴露出去,让其他对象能够进行引用,就完成了这个闭环的解环操作。这也就是常规说的提前暴露对象(缓存,一、二、三级缓存)

三级缓存说明

image.png 解决上图循环依赖的问题一、二级缓存即可解决,三级缓存是用来解决代理对象的问题。Spring在使用的时候可能会配置AOP,如果配置的AOP就需要生成对应的代理对象。
代理对象中应该包含了普通对象的所有功能,如果一个对象需要被代理了,那么此时普通对象就可以不存在,只要代理对象即可
也就是说,在后续创建代理对象之后,就可以使用代理对象来覆盖普通对象,普通对象可以不存在了
那什么时候要调用对象?在调用对象的时候,如果检测到当前对象需要被代理,那么直接创建代理对象覆盖即可。怎么能够在随时需要的时候创建代理对象呢? 类似于观察者,但是不是,我传递进去一个生成代理对象的匿名内部类,当需要调用的时候,直接调用匿名内部类(lambda)来生成代理对,就是类似于回调机制。所以三级缓存里面的value值是生成对象的lambda表达式。
回顾一下初始化包含的环节:

  • 填充属性
  • 执行aware接口所对应的方法
  • 执行beanPostProcessor中的before方法
  • 执行init-method方法
  • 执行beanPostProcessor中的after方法 上述步骤执行完成后是为了获取到一个完整的成品对象,但是在初始化前我们不能确定哪一个对象需要生成代理对象。所以可以将所有bean对象需要的创建代理对象的lambda表达式放到三级缓存中,后续如果我需要调用,直接从三级缓存中调用执行即可,如果不需要,在生成完整对象之后可以把三级缓存中 lambda表达式给清除。

在什么时候要生成具体的代理对象?

  1. 在进行属性注入的时候,调用该对象生成的时候检测是否需要被代理,如果需要,直接创建代理对象
  2. 在整个过程中,没有其他的对象有当前对象的依赖,那么在生成最终的完整对象之前生成代理对象即可(BeanPostProcessor中的after方法)