【面试题系列】高频面试题:Spring 如何解决循环依赖?

简介: Spring是通过递归的方式获取目标bean及其所依赖的bean的;Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。

 Spring整个解决循环依赖问题的实现思路如下图代码。对于整体过程,需要理解两点:

    • Spring是通过递归的方式获取目标bean及其所依赖的bean的;
    • Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。

    结合这两点,也就是说,Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的。

    代码:

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {
      // 实例化当前尝试获取的bean对象,比如A对象和B对象都是在这里实例化的
      BeanWrapper instanceWrapper = null;
      if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
      }
      if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
      }
      // 判断Spring是否配置了支持提前暴露目标bean,也就是是否支持提前暴露半成品的bean
      boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences 
        && isSingletonCurrentlyInCreation(beanName));
      if (earlySingletonExposure) {
        // 如果支持,这里就会将当前生成的半成品的bean放到singletonFactories中,这个singletonFactories
        // 就是前面第一个getSingleton()方法中所使用到的singletonFactories属性,也就是说,这里就是
        // 封装半成品的bean的地方。而这里的getEarlyBeanReference()本质上是直接将放入的第三个参数,也就是
        // 目标bean直接返回
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
      }
      try {
        // 在初始化实例之后,这里就是判断当前bean是否依赖了其他的bean,如果依赖了,
        // 就会递归的调用getBean()方法尝试获取目标bean
        populateBean(beanName, mbd, instanceWrapper);
      } catch (Throwable ex) {
        // 省略...
      }
      return exposedObject;
    }

    image.gif


    相关文章
    |
    2月前
    |
    监控 Java 应用服务中间件
    高级java面试---spring.factories文件的解析源码API机制
    【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
    103 2
    |
    2月前
    |
    缓存 架构师 Java
    图解 Spring 循环依赖,一文吃透!
    Spring 循环依赖如何解决,是大厂面试高频,本文详细解析,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
    图解 Spring 循环依赖,一文吃透!
    |
    1月前
    |
    存储 缓存 Java
    Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
    在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
    57 2
    |
    1月前
    |
    Java 关系型数据库 数据库
    京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
    45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
    |
    4月前
    |
    缓存 Java 开发工具
    Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
    三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
    238 24
    |
    3月前
    |
    设计模式 缓存 Java
    面试题:谈谈Spring用到了哪些设计模式?
    面试题:谈谈Spring用到了哪些设计模式?
    |
    4月前
    |
    缓存 前端开发 Java
    【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
    Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
    |
    4月前
    |
    缓存 Java 数据库
    【Java面试题汇总】Spring篇(2023版)
    IoC、DI、aop、事务、为什么不建议@Transactional、事务传播级别、@Autowired和@Resource注解的区别、BeanFactory和FactoryBean的区别、Bean的作用域,以及默认的作用域、Bean的生命周期、循环依赖、三级缓存、
    |
    3月前
    |
    缓存 Java Spring
    源码解读:Spring如何解决构造器注入的循环依赖?
    本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
    84 1
    |
    4月前
    |
    缓存 Java Spring
    手写Spring Ioc 循环依赖底层源码剖析
    在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
    55 4