参考博客原文地址:

https://www.jb51.net/article/168398.htm

https://www.cnblogs.com/mianteno/p/10692633.html

http://www.pianshen.com/article/4112200143/


1.构造器依赖循环

代码示例:

@Component
public class A {
private B b;
@Autowired
public A(B b) {
this.b=b;
}
}
@Component
public class B {
private C c;
@Autowired
public B(C c) {
this.c = c;
}
}
@Component
public class C {
private A a;
@Autowired
public C(A a) {
this.a=a;
}
}

启动运行后运行结果:

可以看到异常的信息:

//org.springframework.beans.factory.BeanCurrentlyInCreationException
public BeanCurrentlyInCreationException(String beanName) {
super(beanName,
"Requested bean is currently in creation: Is there an unresolvable circular reference?");
}

这种循环依赖没有什么解决办法,因为JVM虚拟机在对类进行实例化的时候,需先实例化构造器的参数,而由于循环引用这个参数无法提前实例化,故只能抛出错误。


2.属性注入依赖循环

代码示例:

@Component
public class A {
@Autowired
private B b;
public A() {
System.err.println(b);
}
}
@Component
public class B {
@Autowired
private C c;
public B() {
System.err.println(c);
}
}
@Component
public class C {
@Autowired
private A a;
public C() {
System.err.println(a);
}
}

启动运行后运行结果:

//程序正常启动,输出如下
null
null
null

结论:

Spring通过将实例化后的对象提前暴露给Spring容器中的singletonFactories,解决了循环依赖的问题


3.源码分析 构造器循环依赖异常步骤及原因:

创建一个Bean的过程是:实例化->初始化(属性)->放到缓存中,如下图

这张图是核心

getSingleton源码:

//首次创建的beanName放入singletonsCurrentlyInCreation中
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}

构造器循环依赖,在初始化C时,需要先实例化A,但是A已经在singletonsCurrentlyInCreation有预实例化的记录了,所以此处抛出异常。

public BeanCurrentlyInCreationException(String beanName) {
super(beanName,
"Requested bean is currently in creation: Is there an unresolvable circular reference?");
}

源码分析 Spring如何解决属性注入 依赖循环问题:

//相关类
org.springframework.beans.factory.support.DefaultListableBeanFactory
org.springframework.beans.factory.support.AbstractBeanFactory
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

可以看到,在实例化后,Bean被添加到singletonFactories中了,所以可以获取到Bean实例,解决了属性循环依赖问题

try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}

4.最终总结:

构造器循环依赖:没有什么解决办法,因为JVM虚拟机在对类进行实例化的时候,需先实例化构造器的参数,而由于循环引用这个参数无法提前实例化,故只能抛出错误。

属性循环依赖:Spring通过将实例化后的对象提前暴露给Spring容器中的singletonFactories,解决了循环依赖的问题

Springboot Bean循环依赖问题的更多相关文章

  1. Spring源码-IOC部分-Spring是如何解决Bean循环依赖的【6】

    实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...

  2. 从源码解读Spring如何解决bean循环依赖

    1 什么是bean的循环依赖 循环依赖的原文是circular reference,指多个对象相互引用,形成一个闭环. 以两个对象的循环依赖为例: Spring中的循环依赖有 3 种情况: 构造器(c ...

  3. Springboot循环依赖实践纪实

    测试的Springboot版本: 2.6.4,禁止了循环依赖,但是可以通过application.yml开启(哈哈) @Lazy注解解决循环依赖 情况一:只有简单属性关系的循环依赖 涉及的Bean: ...

  4. spring3 循环依赖

    循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环.此处不 ...

  5. Spring的循环依赖问题

    spring容器循环依赖包括构造器循环依赖和setter循环依赖,那Spring容器如何解决循环依赖呢?首先让我们来定义循环引用类: 在Spring中将循环依赖的处理分成了3种情况: 构造器循环依赖 ...

  6. DI 之 3.2 循环依赖 (伍)

    3.2.1  什么是循环依赖 循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA, ...

  7. Spring源代码解析 ---- 循环依赖

    一.循环引用: 1. 定义: 循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比方CircularityA引用CircularityB,CircularityB引用Circularit ...

  8. 开涛spring3(3.2) - DI之循环依赖

    3.2.1  什么是循环依赖 循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用 CircleC,CircleC引用CircleA ...

  9. Spring循环依赖问题

    什么是循环依赖? 循环依赖就是循环引用,指两个或多个bean互相持有对方,比如说TestA引用TestB.TestB引用TestA,最终形成一个闭环. 注意:循环依赖不是指循环调用. 循环调用:指方法 ...

随机推荐

  1. Pytorch model saving and loading 模型保存和读取

    It is really useful to save and reload the model and its parameters during or after training in deep ...

  2. MVC webuploader 图片

    AARTO:SaveNoticeAndDocument ~/Scripts/Upload/webuploader-0.1.4/dist/webuploader.js

  3. Django线上部署代码修改失效问题

    记一次django项目的线上部署维护问题,django+nginx 关于nginx反向代理服务器的介绍这里有一篇博客介绍的比较好:nginx的相关介绍 以及当一次客户端请求发出后,uwsig以及uWS ...

  4. python爬虫入门之快递查询

    现在快递遍布生活的角角落落,一个快递其实是信息的集合体,里面包含大量的物流信息,那能不能自己实现一个快递查询的小功能?答案是能的!现在也有别人整理好的快递查询api,比如说快递100,可以通过它提供的 ...

  5. 十二、js去掉空格_比较字符长度_中英文判断_页面初始化_简体字与繁字体判断

    1.去掉字符串前后所有空格 function trimBlank(str){ return str.replace(/(^\s*)|(\s*$)/g, ""); } 2.字符串长度 ...

  6. 机器学习、深度学习中的信息熵、相对熵(KL散度)、交叉熵、条件熵

    信息熵 信息量和信息熵的概念最早是出现在通信理论中的,其概念最早是由信息论鼻祖香农在其经典著作<A Mathematical Theory of Communication>中提出的.如今 ...

  7. MyBatis学习之简单增删改查操作、MyBatis存储过程、MyBatis分页、MyBatis一对一、MyBatis一对多

    一.用到的实体类如下: Student.java package com.company.entity; import java.io.Serializable; import java.util.D ...

  8. 线程高级篇-Lock锁实现生产者-消费者模型

    Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...

  9. 无需重新编译安装PHP扩展的方法

    转自:https://www.jianshu.com/p/ae3c17b0f126 PHP扩展模块通常有两种: PHP官方扩展.如果php通过源码安装(php7),安装的时候未开启,而后来需要开启某个 ...

  10. C语言常用函数

    一.数学函数 调用数学函数时,要求在源文件中包下以下命令行: #include <math.h> 函数原型说明 功能 返回值 说明 int abs( int x) 求整数x的绝对值 计算结 ...