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


    相关文章
    |
    29天前
    |
    SQL 存储 Oracle
    Oracle 面试题及答案整理,最新面试题
    Oracle 面试题及答案整理,最新面试题
    73 0
    |
    29天前
    |
    消息中间件 存储 负载均衡
    RocketMQ 面试题及答案整理,最新面试题
    RocketMQ 面试题及答案整理,最新面试题
    124 4
    |
    29天前
    |
    消息中间件 存储 监控
    RabbitMQ 面试题及答案整理,最新面试题
    RabbitMQ 面试题及答案整理,最新面试题
    108 1
    |
    29天前
    |
    消息中间件 存储 监控
    Kafka 面试题及答案整理,最新面试题
    Kafka 面试题及答案整理,最新面试题
    124 1
    |
    29天前
    |
    Java Nacos Sentinel
    Spring Cloud Alibaba 面试题及答案整理,最新面试题
    Spring Cloud Alibaba 面试题及答案整理,最新面试题
    136 0
    |
    17天前
    |
    缓存 算法 Java
    开发必懂的Spring循环依赖图解 Spring 循环依赖
    开发必懂的Spring循环依赖图解 Spring 循环依赖
    18 1
    |
    29天前
    |
    存储 安全 API
    Swift 面试题及答案整理,最新面试题
    Swift 面试题及答案整理,最新面试题
    83 0
    |
    29天前
    |
    存储 安全 Java
    Android 面试题及答案整理,最新面试题
    Android 面试题及答案整理,最新面试题
    35 2
    |
    29天前
    |
    存储 关系型数据库 MySQL
    MySQL 面试题及答案整理,最新面试题
    MySQL 面试题及答案整理,最新面试题
    87 0
    |
    Java 关系型数据库 MySQL
    06_spring_ 依赖注入| 学习笔记
    快速学习 06_spring_ 依赖注入