大厂面试题-Spring如何解决循依赖问题

目录

考察目的

问题解析

问题解答


考察目

这个问题考察的求职者年限还挺广的,工作1年到工作7年之间都会遇到。

考察目的有三个:

    1、Spring是Java开发的基础应用框架,所以考察的是基本功

    2、考察技术深度,判断你的能力高低以及

    3、作为人才筛选的区分度

因此对于个问题,不仅仅要回答原因,还需要有自己的思考和总结。

另外还需要注意,这个问题问的是Spring如何解决循环依赖,因此对于Spring无法解决的循环依赖我们没必要在这里展开。

下面我们来分析一下这个问题的产生背景和解决方案。

题解析

循环依赖是指一个或多个Bean实例之间存在直接或间接的依赖关系,构成循环调用。通常表现为三种形态

      1、(如图)互相依赖,也就是A依赖B,B依赖A

      2、(如图)间接依赖,两个以上的Bean存在间接依赖关系造成循环调用。

      3、(如图)自我依赖,自己依赖自己造成了循环依赖。

Spring也考虑到了这方面的问题,所以它设计了三级缓存来解决部分循环依赖的题。

所谓三级缓存,其实就是用来存放不同类型的Bean。

    1、第一级缓存存放完全初始化好的Bean,这个Bean可以直接使用了

    2、第二级缓存存放原始的Bean对象,也就是说Bean里面的属性还没有进行赋值

    3、第三级缓存存放Bean工厂对象,用来生成原始Bean对象并放入到二级缓存中假设BeanABeanB存在循环依赖,那么在三级缓存的设计下,我画了这样一个图来描述工作原理。

    4、初始化BeanA,先把BeanA实例化,然后把BeanA包装成ObjectFactory对象保存到三级缓存中。

    5、接着BeanA开始对属性BeanB进行依赖注入,于是开始初始化BeanB,同样做两件事,创建BeanB实例,以及加入到三级缓存。

    6、然后,BeanB也开始进行依赖注入,在三级缓存中找到了BeanA,于是完成BeanA的依赖注入

    7、BeanB初始化成功以后保存到一级缓存,于是BeanA可以成功拿到BeanB的实例,从而完成正常的依赖注入。

整个流程看起来复杂,但是它的核心思想就是把Bean的实例化和Bean中属性的依赖注入这两个过程分离出来。

不过要注意的是,Spring本身只能解决单实例存在的循环引用问题,但是存在以下四种情况需要人为干预:

    1、多实例的Setter注入导致的循环依赖,需要把Bean改成单例。

    2、构造器注入导致的循环依赖,可以通过@Lazy注解

    3、DependsOn导致的循环依,找到注解循环依赖的地方,迫使它不循环依赖。

    4、单例的代理对象Setter注入导致的循环依赖,

        a、可以使用@Lazy注解,

        b、或者使用@DependsOn注解指定加载先后关系。

在实际开发中,出现循环依赖的根本原因还是在代码设计的时候,因为模块的耦合度较高,依赖关系复杂导致的,我们应该尽可能的从系统设计角度去考虑模块之间的依赖关系,避免循环依赖的问题。

问题解答

Spring设计了三级缓存来解决循环依赖问题

    1、第一级缓存里面存储完整的Bean实例,这些实例是可以直接被使用的。

    2、第二级缓存里面存储的是实例化以后,但是还没有设置属性值的Bean实例,也就是Bean里面的依赖注入还没有做。

    3、第三级缓存用来存放Bean工厂,它主要用来生成原始Bean对象并且放到第二级缓存里面。

三级缓存的核心思想,就是把Bean的实例化,和Bean里面的依赖注入进行分离。采用一级缓存存储完整的Bean实例,采用二级缓存来存储不完整的Bean实例,通过不完整的Bean实例作为突破口,解决循环依赖的问题。

至于第三级缓存,主要是解决代理对象的循环依赖问题。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值