【面试题系列】高频面试题: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


    相关文章
    |
    25天前
    |
    前端开发 安全 Java
    2025春招,Spring 面试题汇总
    本文详细整理了2025年春招必备的Spring面试题,分为基础和高级两大部分,帮助求职者全面掌握Spring相关知识点,结合实际项目经验,提升面试成功率。内容涉及Spring框架、AOP、事务管理、数据库集成、Spring Boot、Spring Security、微服务架构等,助力你在春招中脱颖而出。
    161 0
    |
    3月前
    |
    监控 Java 应用服务中间件
    高级java面试---spring.factories文件的解析源码API机制
    【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
    132 2
    |
    2月前
    |
    存储 缓存 Java
    Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
    在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
    74 2
    |
    2月前
    |
    Java 关系型数据库 数据库
    京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
    45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
    |
    4月前
    |
    设计模式 缓存 Java
    面试题:谈谈Spring用到了哪些设计模式?
    面试题:谈谈Spring用到了哪些设计模式?
    |
    5月前
    |
    缓存 前端开发 Java
    【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
    Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
    |
    5月前
    |
    缓存 Java 数据库
    【Java面试题汇总】Spring篇(2023版)
    IoC、DI、aop、事务、为什么不建议@Transactional、事务传播级别、@Autowired和@Resource注解的区别、BeanFactory和FactoryBean的区别、Bean的作用域,以及默认的作用域、Bean的生命周期、循环依赖、三级缓存、
    |
    4月前
    |
    Java 程序员 Spring
    Spring事务的1道面试题
    每次聊起Spring事务,好像很熟悉,又好像很陌生。本篇通过一道面试题和一些实践,来拆解几个Spring事务的常见坑点。
    Spring事务的1道面试题
    |
    4月前
    |
    XML 前端开发 Java
    Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
    本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
    320 0
    Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
    |
    5月前
    |
    缓存 Java Spring
    手写Spring Ioc 循环依赖底层源码剖析
    在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
    66 4

    热门文章

    最新文章