【spring源码-9】bean的实例化(6)循环依赖

205 阅读2分钟

上一篇【spring源码-8】bean的实例化(5)FactoryBean接口

引题

简单示例: A、B 互相依赖如下: image.png image.png 运行如下: image.png 结果没有报错, 思考:

实例化 A 时,发现依赖注入了 B,就需要实例化 B;
实例化 B 时,又发现依赖注入了 A,就需要实例化 A,但此时已经是实例化 A 的流程,按理说会出现死循环,为何没有报错,spring是如何处理的?

流程解析

循环依赖.png

思考:二级缓存也可以解决循环依赖问题,spring为什么用了三级缓存?

假设只有二级缓存,AB 相互依赖,但此时 A 存在代理对象 Proxy-A,B 要注入的是 Proxy-A。
实例化 A 需要 B(此时将 A 对象放入二级缓存),然后去实例化B,发现需要注入A,刚好二级缓存中就有个A,注入成功。但是此时B注入的并非是 Proxy-A,而是对象 A

回到spring的三级缓存:
三级缓存中存储的并非是bean对象,而是bean工厂。

image.png image.png 还记得从三级缓存中获取bean实例么?并非是直接获取到一个bean,而是先获取到了工厂对象,然后调用 getObject() 获取到bean实例。

image.png getObject() 调用到 getEarlyBeanReference()
这里也是 beanPostProcessor 的应用,代理对象会在这里生成。 image.png 所以三级缓存是解决循环依赖时涉及到代理对象的问题。

总结

  • spring用了“提前暴露”的设计思想来处理循环依赖问题:
    实例化bean时,在创建对象之后、依赖注入之前,会将当前空对象放入三级缓存中,供需要注入的对象在其依赖 > 注入时使用。
  • 二级缓存本身可以解决循环依赖问题,三级缓存是解决循环依赖时涉及到需要依赖代理对象的问题。

注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。

下一篇【spring源码-10】bean的实例化(7)AOP-早期的aop