《面试1v1》Spring循环依赖

839 阅读3分钟

我是 javapub,一名 Markdown 程序员从👨‍💻,八股文种子选手。

面试官: 小伙子,听说你对 Spring 循环依赖比较熟悉,是真的吗?

候选人: 王哥,不敢说很熟悉,但有一定了解,请王哥考考我。

面试官: 那好,首先简单说一下,什么是 Spring 循环依赖?

候选人: Spring 循环依赖指的是 BeanA 依赖 BeanB,而 BeanB 也直接或间接依赖 BeanA,两者之间形成依赖循环。这会导致 Bean 无法正常实例化。

面试官: circular dependencies,确实是这样。Spring Bean 的循环依赖有哪些场景?

候选人: 主要有三种场景:

  1. 构造器循环依赖:BeanA 的构造器注入 BeanB,BeanB 的构造器又注入 BeanA。
  2. Setter 循环依赖:BeanA 在 setter 方法中注入 BeanB,BeanB 的 setter 方法又注入 BeanA。
  3. 代理循环依赖:BeanA 依赖 BeanB 的代理对象,BeanB 依赖 BeanA 的代理对象。

面试官: 那 Spring 是如何解决循环依赖问题的呢?

候选人: Spring 采用提前暴露对象的方式解决循环依赖,主要通过 AOP 功能和 SmartInstantiationAwareBeanPostProcessor#postProcessAfterInstantiation 方法实现。

  1. 对代理循环依赖,Spring 会首先创建目标对象,然后再创建代理对象。
  2. 对 Setter 循环依赖,Spring 会在对象创建完成后,提前将对象注入到 BeanFactory 中。然后在注入依赖时,直接从 BeanFactory 中获取已经提前实例化的对象。
//AbstractAutowireCapableBeanFactory#doCreateBean
    ...
     // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
    Object bean = resolveBeforeInstantiation(beanName, mbd);
    if (bean != null) {
        return bean;
    }
    ...  
    // Allow post-processors to modify the merged bean definition.
    bean = applyBeanPostProcessorsAfterInstantiation(bean, beanName);
    ... 
  1. 对构造器循环依赖,Spring 在实例化对象后,会提前暴露一个 ObjectFactory,再从 ObjectFactory 中获取目标对象完成依赖注入。

面试官: 那么,Spring 循环依赖会带来什么问题?

候选人: Spring 循环依赖主要会带来以下问题:

  1. 破坏 Bean 的单例性。因为循环依赖导致一个 Bean 被实例化多次,破坏了 Spring 容器中 Bean 的唯一性。
  2. 容器无法正常结束注入过程。循环依赖会导致 Bean 无法完全实例化,一直在循环注入过程中,无法结束。
  3. 降低程序的可读性和维护性。循环依赖关系使得程序难以理解,也难以维护。

面试官: 那么,如何避免 Spring 循环依赖呢?

候选人: 主要有以下几种方式可以避免 Spring 循环依赖:

  1. 编程方式避免。在 Bean 中提供 set 方法,但不在构造器中注入依赖。这样只有在 Bean 完全实例化后,才会注入依赖对象。
  2. 构造器注入避免。只使用构造器注入,不用 Setter 方法注入。因为构造器是在 Bean 实例化阶段完成的,避免了循环依赖。
  3. 避免过于提前暴露 Bean。如果一个 Bean 不需要频繁使用,不要将其设置为 Singleton,推迟其实例化时间。
  4. 分模块避免。将循环依赖的 Bean 拆分到不同的模块中,模块间采用接口隔离,避免循环依赖。
  5. 采用重构手段。如果上述方式都不可行,那么需要通过重构来避免循环依赖。比如拆分过于庞大的 Bean 为多个小 Bean 等。

面试官: 不错,总结得很全面。看来你对 Spring 循环依赖还是比较清晰的,加油!

候选人: 谢谢 王哥 的提问,让我对 Spring 循环依赖有了更深入的认识。我会继续努力学习的!

24.jpg

最近我在更新《面试1v1》系列文章,主要以场景化的方式,讲解我们在面试中遇到的问题,致力于让每一位工程师拿到自己心仪的offer,感兴趣可以关注JavaPub追更!


《面试1v1》 连载中...


🎁目录合集:

Gitee:https://gitee.com/rodert/JavaPub

GitHub:https://github.com/Rodert/JavaPub

javapub.net.cn