spring循环依赖

Spring中的循环依赖是指在Spring容器中,两个或多个Bean之间相互依赖,形成了一个闭环的依赖关系。以下是关于Spring循环依赖的详细介绍:

循环依赖的类型

  • 构造器循环依赖:Bean A的构造函数中需要注入Bean B,而Bean B的构造函数中又需要注入Bean A,这种情况在Spring中是无法解决的,会导致BeanCurrentlyInCreationException异常。因为构造器注入是在Bean实例化的过程中进行的,在这种循环依赖下,Spring无法完成Bean的实例化。
  • 字段注入循环依赖:Bean A通过字段注入的方式依赖Bean B,而Bean B又通过字段注入依赖Bean A。
  • setter方法循环依赖:Bean A通过setter方法注入Bean B,Bean B又通过setter方法注入Bean A。这种情况与字段注入类似,Spring容器在处理时也会面临挑战。

Spring解决循环依赖的原理

Spring通过三级缓存来解决循环依赖问题,这三级缓存分别是:

  • 一级缓存singletonObjects,用于存储已经创建好的单例Bean对象,是一个ConcurrentHashMap。当Spring创建好一个单例Bean后,会将其放入这个缓存中,以后再获取该Bean时,直接从这里获取。
  • 二级缓存earlySingletonObjects,用于存储早期暴露的Bean对象。在Bean的创建过程中,当Bean完成实例化但还未进行属性填充等后续操作时,会将其提前放入二级缓存。这个缓存主要是为了解决循环依赖时,让其他Bean能够提前获取到正在创建中的Bean的引用。
  • 三级缓存singletonFactories,用于存储Bean工厂对象。在创建Bean时,如果发现该Bean可能存在循环依赖,会将一个能够生成该Bean的工厂对象放入三级缓存。其他Bean在需要依赖该Bean时,可以通过这个工厂对象获取到早期的Bean引用。

在Spring创建Bean的过程中,会按照以下步骤利用三级缓存来处理循环依赖:

  1. 首先从一级缓存singletonObjects中获取Bean,如果能获取到,说明Bean已经创建完成,直接返回。
  2. 如果一级缓存中没有,就从二级缓存earlySingletonObjects中获取。如果能获取到,说明这是一个早期暴露的Bean,也直接返回。
  3. 如果二级缓存中也没有,就从三级缓存singletonFactories中获取对应的Bean工厂。如果有,就通过工厂获取早期的Bean引用,并将其放入二级缓存,同时从三级缓存中移除。
  4. 如果三级缓存中也没有,就开始创建Bean。在创建过程中,如果发现Bean存在依赖其他Bean的情况,就会先去创建依赖的Bean,然后再回来继续完成当前Bean的创建。在创建依赖的Bean时,同样会按照上述步骤检查缓存,处理可能存在的循环依赖。

示例代码

以下是一个简单的Spring循环依赖的示例代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class A {
    @Autowired
    private B b;

    public A() {
        System.out.println("A的构造函数");
    }

    public void doSomething() {
        System.out.println("A执行某个操作");
    }
}

@Component
public class B {
    @Autowired
    private A a;

    public B() {
        System.out.println("B的构造函数");
    }

    public void doSomething() {
        System.out.println("B执行某个操作");
    }
}

在上述代码中,A类依赖B类,B类又依赖A类,形成了循环依赖。如果在Spring项目中运行这段代码,Spring容器会通过三级缓存机制来解决这个循环依赖问题,确保AB都能正确创建和注入。

注意事项

  • 多例Bean的循环依赖:Spring默认是不支持多例Bean的循环依赖的,因为多例Bean在每次获取时都会创建一个新的实例,无法像单例Bean那样通过缓存来解决循环依赖。
  • 延迟加载:可以使用@Lazy注解来延迟Bean的加载,对于一些可能存在循环依赖但又不是在启动时就必须使用的Bean,可以通过延迟加载来避免循环依赖问题在启动时就暴露出来。
#面试被问“你的缺点是什么?”怎么答##JAVA面经##面试时最害怕被问到的问题##牛客创作赏金赛#
职保镖-扶你上马 文章被收录于专栏

知识分享,交天下朋友,扶你上马,送你一层,职业规划,面试指导、高薪谈判、背调辅助

全部评论

相关推荐

评论
1
6
分享

创作者周榜

更多
牛客网
牛客企业服务