Spring 循环依赖解析(上)

简介: Spring 现在其实是我们 Java 程序开发离不开的基础框架,个人觉得除了 JDK 我们用得最多的 Java 中间件就是 Spring ,今天我们一起来学习一下 Spring 的循环依赖。

常见问题


  • 你解释一下 spring 中的三级缓存?


  • 三级缓存分别是什么?三个 Map 有什么异同?


  • 什么是循环依赖?请谈谈?你看过 spring 的源码吗?一般我们说的是 spring  容器是什么?


  • 多例的情况下,循环依赖问题为什么无法解决?


什么是循环依赖?


多个 bean 之间相互依赖,形成闭环。 比如:A 依赖于 B, B 依赖于 C , C 依赖于 A示例代码


public class T1 {
  class A {
    B b;
  }
  class B {
    C c;
  }
  class C {
    A a; 
  }
}


比如:A 依赖于 B, B 依赖于 C , C 依赖于 A


通常来说,如果问 Spring 容器内部如何解决循环依赖,一定是指默认的单例 Bean 中, 属性相互引用的场景。


@Component
public class A {
    @Autowired
  private B b;
}
@Component
public class B {
    @Autowired
  private C c;
}
@Component
public class C {
    @Autowired
  private A a;
}


循环依赖说明


官方说明


参考官方说,下面会有官网链接


image.png


官网链接:docs.spring.io/spring-fram…


结论


构造方法注入:不支持循环依赖。结论:我们 AB 循环依赖问题。只要 A 的方式是 setter 且 singleton 就不会有循环依赖问题。


BeanCurrentlyInCreationException


循环依赖异常的定义如下所示,如果出现循环依赖,我们在启动/运行过程中会报这个错误。


image.png


依赖注入的两种方式


方式一:构造器方式注入依赖


@Component
public class ServiceA{
    private ServiceB serviceB;
    public ServiceA(ServiceB serverB) {
       this.serivceB = serviceB;
    }     
}
@Component
public class ServiceB{
    private ServiceA serviceA;
    public ServiceB(ServiceA serviceA) {
       this.serviceA = serviceA;
    }     
}


构造器循环依赖是无法解决的,你想让构造器注入支持循环依赖,是不可能的。


方式二:以 set 方式注入依赖


@Component
public class ServiceA{
    private ServiceB serviceB;
    public setServiceB(ServiceB serverB) {
       this.serivceB = serviceB;
    }     
}
@Component
public class ServiceB{
    private ServiceA serviceA;
    public setServiceB(ServiceA serviceA) {
       this.serviceA = serviceA;
    }     
}


案例演示(基于 Spring 容器的循环依赖)


普通的 Java 基础编码A  类、B 类


@Data
public class A{
  private B b;
  public A() {
     System.out.println("----- A create success");
  }
}
@Data
public class B{
  private a a;
  public B() {
     System.out.println("------ B create success");
  }    
}


循环依赖解决


A a = new A();
B b = new B();
a.setB(b);
b.setA(a);


基于 Spring 容器的循环依赖


  • 默认的单例(singleton)的场景是支持循环依赖的,不报错


  • 原型(prototype)的场景是不支持循环依赖的, 会报错


代码演示


  • 循环依赖代码


@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class A {
    @Autowired
    private B b;
}
@Component
public class B {
    @Autowired
    private A a;
}


  • 默认单例,修改为原型


// 增加注解
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)


  • 一段测试程序


class BTest {
    @Configuration
    @Import({A.class, B.class})
    public static class TestConfig {
    }
    @Test
    public void currentlyincreation() {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(TestConfig.class);
        // 这里要获取 bean 一下,如果不去主动获取,可能是由于惰性加载没有执行,不会报错
        A a = applicationContext.getBean(A.class);
        System.out.println(a);
    }
}


  • 循环依赖异常


image.png


相关文章
|
1天前
|
canal 缓存 关系型数据库
Spring Boot整合canal实现数据一致性解决方案解析-部署+实战
Spring Boot整合canal实现数据一致性解决方案解析-部署+实战
|
1天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
7天前
|
存储 缓存 Java
Spring解决循环依赖
Spring解决循环依赖
|
13天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
19 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
13天前
|
XML Java 数据格式
从入门到精通:Spring基础注解的全面解析
从入门到精通:Spring基础注解的全面解析
30 2
从入门到精通:Spring基础注解的全面解析
|
13天前
|
Java 数据库 Spring
切面编程的艺术:Spring动态代理解析与实战
切面编程的艺术:Spring动态代理解析与实战
26 0
切面编程的艺术:Spring动态代理解析与实战
|
Java 关系型数据库 MySQL
06_spring_ 依赖注入| 学习笔记
快速学习 06_spring_ 依赖注入
|
28天前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
43 0
|
2月前
|
缓存 Java Maven
Spring Boot自动配置原理
Spring Boot自动配置原理
48 0
|
1月前
|
缓存 安全 Java
Spring Boot 面试题及答案整理,最新面试题
Spring Boot 面试题及答案整理,最新面试题
111 0

推荐镜像

更多