Spring循环依赖

简介: Spring循环依赖

一、正常的bean创建生命周期

  1.   实例化
  2.   属性填充
  3.   初始化前、初始化
  4.   初始化(生成AOP代理对象)
  5.   放入单例池

二、 循环依赖的产生

     创建A对象时需要注入B对象,创建B对象是也要注入A对象

三、解决方式

     spring解决循环的方式是使用了三级缓存:

1. singletonObjects :缓存经过了 完整生命周期 的bean

2. earlySingletonObjects :缓存 未经过完整生命周期的bean ,如果某个bean出现了循环依赖,

就会 提前 把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果

要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入

earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是

没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是 未经过完整

生命周期的bean。

3. singletonFactories :缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean

的生成过程中,经过 实例化 得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达

式,并保存到三级缓存中,这个Lambda表达式 可能用到,也可能用不到 ,如果当前Bean没有出

现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后

直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖(当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行Lambda表达式得到一个对象,并把得到的对象放入二级缓存(如果当前Bean需要AOP,那么执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象)。

4. 其实还要一个缓存,就是 earlyProxyReferences ,它用来记录某个原始对象是否进行过AOP

了。避免后续AOP被重复执行。

详细过程:

 1. 创建A时,先将A对象名称添加到createset集合中,以标记为A对象正在创建中。

 2. 实例化A,得到一个A对象的 singletonFactories对象,这是一段lamba表达式,只有出现循环依赖时才会执行,得到A的原始对象。

 3. 填充B属性,先去单例池 singletonObjects(一级缓存)中找,没找到去createset集合中找,找到了说明B出现了循环依赖,此时接着去 earlySingletonObjects(二级缓存)中找,如果找不到则去singletonFactories(三级缓存)中找,去singletonFactories(三级缓存)中找实际上是执行最初的那段lamba表达式,得到B的代理对象或者原始对象,放入earlySingletonObjects中。并将对象从三级缓存清除。将B对象赋值给B属性。

 4. 填充其他属性。  

总结:

  1.  解决循环依赖的关键是singletonFactories,它打破了循环依赖的死循环,它只有在出现循环依赖时才执行,返回的是对象的原始对象或代理对象。

  2. earlySingletonObjects最大的作用是保证了在属性注入过程中的单例特性,因为有可能出现C也依赖的A,为了避免在这种情况下又去生成代理对象,就直接去earlySingletonObjects这个缓存中找。

  3. 只有在出现了循环依赖的情况下才会打破Bean生命周期的设 计,如果一个Bean没有出现循环依赖,那么它还是遵守了Bean的生命周期的设计的。

 

相关文章
|
9月前
|
监控 安全 Java
解决 Spring Boot 中 SecurityConfig 循环依赖问题的详解
本文详细解析了在 Spring Boot 中配置 `SecurityConfig` 时可能遇到的循环依赖问题。通过分析错误日志与代码,指出问题根源在于 `SecurityConfig` 类中不当的依赖注入方式。文章提供了多种解决方案:移除 `configureGlobal` 方法、定义 `DaoAuthenticationProvider` Bean、使用构造函数注入以及分离配置类等。此外,还讨论了 `@Lazy` 注解和允许循环引用的临时手段,并强调重构以避免循环依赖的重要性。通过合理设计 Bean 依赖关系,可确保应用稳定启动并提升代码可维护性。
707 0
|
10月前
|
Java Maven 微服务
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的 maven 依赖
在项目中使用Swagger2工具时,需导入Maven依赖。尽管官方最高版本为2.8.0,但其展示效果不够理想且稳定性欠佳。实际开发中常用2.2.2版本,因其稳定且界面友好。以下是围绕2.2.2版本的Maven依赖配置,包括`springfox-swagger2`和`springfox-swagger-ui`两个模块。
431 0
|
10月前
|
缓存 Java 应用服务中间件
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——依赖导入和Thymeleaf相关配置
在Spring Boot中使用Thymeleaf模板,需引入依赖`spring-boot-starter-thymeleaf`,并在HTML页面标签中声明`xmlns:th="http://www.thymeleaf.org"`。此外,Thymeleaf默认开启页面缓存,开发时建议关闭缓存以实时查看更新效果,配置方式为`spring.thymeleaf.cache: false`。这可避免因缓存导致页面未及时刷新的问题。
401 0
|
缓存 架构师 Java
图解 Spring 循环依赖,一文吃透!
Spring 循环依赖如何解决,是大厂面试高频,本文详细解析,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
图解 Spring 循环依赖,一文吃透!
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
1565 24
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
297 2
|
存储 缓存 Java
面试问Spring循环依赖?今天通过代码调试让你记住
该文章讨论了Spring框架中循环依赖的概念,并通过代码示例帮助读者理解这一概念。
面试问Spring循环依赖?今天通过代码调试让你记住
|
缓存 Java Spring
源码解读:Spring如何解决构造器注入的循环依赖?
本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
834 1
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
157 4
|
缓存 Java Spring
spring如何解决循环依赖
Spring框架处理循环依赖分为构造器循环依赖与setter循环依赖两种情况。构造器循环依赖不可解决,Spring会在检测到此类依赖时抛出`BeanCurrentlyInCreationException`异常。setter循环依赖则通过缓存机制解决:利用三级缓存系统,其中一级缓存`singletonObjects`存放已完成的单例Bean;二级缓存`earlySingletonObjects`存放实例化但未完成属性注入的Bean;三级缓存`singletonFactories`存放创建这些半成品Bean的工厂。
215 2