• Spring源码学习笔记9——构造器注入及其循环依赖


    Spring源码学习笔记9——构造器注入及其循环依赖

    一丶前言

    前面我们分析了spring基于字段的和基于set方法注入的原理,但是没有分析第二常用的注入方式(构造器注入)(第一常用字段注入),并且在循环依赖问题上构造器注入常被说spring无法解决构造器注入的循环依赖,下面我们来分析构造器注入和其循环依赖的源码

    二丶构造器依赖注入

    在spring初始化每一个非抽象,单例,非懒加载的bean的时候,会调用createBeanInstance方法去创建bean的实例,在使用默认的策略——无参构造or CGLIB生成子类对象的方式之前,先会使用所有的SmartInstantiationAwareBeanPostProcessor 来判断是否有用户指定的后置处理器

    1.循环调用所有的SmartInstantiationAwareBeanPostProcessor实现类来推断该使用哪个构造器

    这里重点是使用到了AutowiredAnnotationBeanPostProcessor来推断

    2.AutowiredAnnotationBeanPostProcessor 推断构造器的逻辑

    首先AutowiredAnnotationBeanPostProcessor 有一个缓存key是bean类型,value是之前推断的所有构造器数组。自然是一波双if+synchronized方式来读缓存中内容,缓存没有命中再进行推断

    none
    遍历每一个构造器(这里省去了spring对Kotlin语言支持的部分)
    1.获取当前构造器上面的@Autowired 和  @Value 注解
    2.如果注解信息为空,且当类是一个被CGLIB代理后的类,
    会获取父类构造器上面的注解(要求父类构造器和当前遍历到的构造器参数类型顺序相同)
    3.如果注解信息不为空,会检查 required 属性的信息
    (spring还支持ejb等的注解,所有这里检查require的信息)像@Autowired 和  @Value这种不包含required属性的注解会默认是required为true,
    并且记录当前构造器为候选者,也就是说有注解的才算在候选者
    4.如果存在多个required=true的构造器抛出异常,
    否则使用遍历记录当前required=true的构造器
    5.如果候选者不为空,required=true的构造器为空
    (一般这种情况是标注了EJB的注解指定required为false)spring会把无参构造加入到候选者中
    6.如果原来类只定义了一个有参构造,那么使用这个有参构造
    
    如果不考虑EJB中的依赖注入注解
    那么就是如果构造器有@Autowired or @Value那么默认使用它
    如果定义了一个有参构造那么使用这个有参构造
    
    其他情况一律返回null(后续spring可能使用无参构造or CGLIB生成子类的方式)

    3.使用构造器进行依赖注入的逻辑

    推断出使用哪个构造器之后,spring调用autowireConstructor方法进行构造器注入,具体逻辑委托给ConstructorResolver的autowireConstructor方法,最终解析依赖注入参数的在createArgumentArray方法中进行,一般是调用resolveAutowiredArgument方法

    最终还是殊途同归的调用到了beanFactory的resolveDependency方法

    4.实例化对象

    这一步还是调用的instantiate方法

    三丶为什么构造器的循环依赖spring无法解决

    1.构造方法注入无法解决循环依赖的情况及其原因

    如果是这种循环依赖的情况spring是无法解决循环依赖的,下面是这种循环依赖出现时候的代码流程

    问题出现在beforeSingletonCreation方法中

    在spring创建bean的之前使用了set维护正在创建bean的名称,B需要A,再次创建A的时候就发现set中原本存在A,这时候就是无法解决循环依赖的情况,会抛出异常

    同理这种情况也是不可以解决的

    2.构造方法注入可以解决循环依赖的情况及其原因

    这种情况下spring又是可以解决循环依赖的

    原因是A是可以成功使用无参构造实例化的,所以B需要A的时候可以在三级缓存拿到A的ObjectFactory,调用后得到A,而不是再次创建A

    none
    我们可以得到结论
    
    如果加载顺序是A然后B,那么A只能是字段注入or方法注入,不能是构造器注入
    B无所谓那种注入方式

    __EOF__

  • 本文作者: Cuzzz
  • 本文链接: https://www.cnblogs.com/cuzzz/p/16538845.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    Java对象的相等判定问题与equals方法解析
    53_Pandas中的条件替换值(where, mask)
    使用RAMMap+PoolMon分析Windows内存使用异常问题
    MySQL-常用数据库操作SQL汇总
    java计算机毕业设计婚恋网站MyBatis+系统+LW文档+源码+调试部署
    跨境电商系统商城源码定制开发的优势与需求
    数据分析师的Windows装机必备软件
    《UML和模式应用(原书第3版)》2024新修订译本部分截图
    516TX 336A4940DNP516TX 具有用于联网工业以太网协议
    Git Flow 的正确使用姿势
  • 原文地址:https://www.cnblogs.com/cuzzz/p/16538845.html