写点什么

Spring 项目中如何正确处理对象依赖

作者:技术小生
  • 2022 年 7 月 17 日
  • 本文字数:1101 字

    阅读完需:约 4 分钟

Spring项目中如何正确处理对象依赖

写在前面

目前,Spring 框架在互联网公司使用频繁。Spring 的核心功能之一就是 IOC(依赖注入)。但是每个人处理依赖注入的方式都不太一样,比如通过构造器注入、通过 Setter 方法注入等。到底如何选择呢?

内容核心

就我个人而言,我更喜欢使用 Setter 方法进行对象的注入。这种注入的方式可以避免循环依赖错误的发生。

循环依赖是什么

循环依赖其实是循环引用,也就是两个或两个以上的 bean 互相持有对方,形成闭环。比如:A 对象依赖 B 对象,B 对象依赖 C 对象,而 C 对象又依赖于 A 对象。

Spring 循环依赖场景主要有两种:

  • 构造器的循环依赖(无法解决)

  • 字段属性的循环依赖

如何解决循环依赖

  • Spring 中的单例对象的创建分为三个步骤:

第一步:createBeanInstance,通过 Bean 的构造方法实例化对象,并没有注入对象的属性

第二步:populateBean,进行实例对象属性的注入

第三步:initializeBean 调用 Spring 中的 init 方法,完成实例对象的创建。(xml 中的 init-method 属性中的所对应的方法;注解 @ PostConstruct 修饰的方法)

  •  Spring 为解决循环依赖问题,使用了三级缓存。

singletonObjects:单例对象的 Cache

singletonFactories:单例对象工厂的 Cache,用于存储在 spring 内部所使用的 beanName->对象工厂的引用。

earlySingletonObjects:提前曝光的单例对象的 cache,用于存储在创建 Bean 早期对创建的原始 bean 的一个引用。

  • 怎么使用这三级缓存,使用情况都集中于 DefaultSingletonBeanRegistry 类的 getSingleton(String beanName, boolean allowEarlyReference)方法中,具体代码流程如图:

那这么做为什么能解决 Spring 中的循环依赖问题

其实,在真正创建这个实例对象之前,这个对象已经产生了。只不过,当时只是通过构造方法进行实例化,并未对其属性进行注入,所以 Spring 提前将其曝光出来。比如:

对象 A 首先完成了初始化的第一步,并且将自己提前曝光到 singtonFactories 中,而此时要进行初始化的第二步的时候,发现自己依赖对象 B,而去尝试 get(B),发现 B 还未被创建,所以进行对象 B 的创建。B 在完成初始化第一步之后,发现自己依赖对象 A,尝试去 get(A),尝试一级缓存 singletonObjects 没有,二级缓存 earlySingletonObjects 也没有,尝试三级缓存 singletonFactories,由于 A 提前曝光到 singletonFactories 中,所以 B 能够通过 ObjectFactory.getObject()方法拿到对象 A,B 完成初始化过程之后,将自己放到 singletonObjects 中。此时,对象 A 获取到对象 B,顺利完成自己的初始化过程,进入一级缓存 singletonObjects 中。完成两个循环依赖对象的初始化。

总结

其实研究源码的目的,就是为了更好地解决系统中发生的问题。在编码过程中,提前将可能的问题处理掉。这样,在上线后,才不至于事故频发。

发布于: 刚刚阅读数: 3
用户头像

技术小生

关注

业务应用架构专家 2019.10.08 加入

主要负责公司内部系统的应用架构设计与落地。擅长Java语言开发,熟悉Python、Shell等。精通K8S等云原生相关技术。

评论

发布
暂无评论
Spring项目中如何正确处理对象依赖_spring_技术小生_InfoQ写作社区