Spring 如何解决循环依赖问题?
1
过程演示
@Component
public class A {
private B b;
public void setB(B b) {
this.b = b;
}
}
@Component
public class B {
private A a;
public void setA(A a) {
this.a = a;
}
}
2
源码讲解
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 尝试通过bean名称获取目标bean对象,比如这里的A对象
Object sharedInstance = getSingleton(beanName);
// 我们这里的目标对象都是单例的
if (mbd.isSingleton()) {
// 这里就尝试创建目标对象,第二个参数传的就是一个ObjectFactory类型的对象,这里是使用Java8的lamada
// 表达式书写的,只要上面的getSingleton()方法返回值为空,则会调用这里的getSingleton()方法来创建
// 目标对象
sharedInstance = getSingleton(beanName, () -> {
try {
// 尝试创建目标对象
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
throw ex;
}
});
}
return (T) bean;
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 尝试从缓存中获取成品的目标对象,如果存在,则直接返回
Object singletonObject = this.singletonObjects.get(beanName);
// 如果缓存中不存在目标对象,则判断当前对象是否已经处于创建过程中,在前面的讲解中,第一次尝试获取A对象
// 的实例之后,就会将A对象标记为正在创建中,因而最后再尝试获取A对象的时候,这里的if判断就会为true
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 这里的singletonFactories是一个Map,其key是bean的名称,而值是一个ObjectFactory类型的
// 对象,这里对于A和B而言,调用图其getObject()方法返回的就是A和B对象的实例,无论是否是半成品
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 获取目标对象的实例
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 实例化当前尝试获取的bean对象,比如A对象和B对象都是在这里实例化的
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 判断Spring是否配置了支持提前暴露目标bean,也就是是否支持提前暴露半成品的bean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences
&& isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 如果支持,这里就会将当前生成的半成品的bean放到singletonFactories中,这个singletonFactories
// 就是前面第一个getSingleton()方法中所使用到的singletonFactories属性,也就是说,这里就是
// 封装半成品的bean的地方。而这里的getEarlyBeanReference()本质上是直接将放入的第三个参数,也就是
// 目标bean直接返回
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
try {
// 在初始化实例之后,这里就是判断当前bean是否依赖了其他的bean,如果依赖了,
// 就会递归的调用getBean()方法尝试获取目标bean
populateBean(beanName, mbd, instanceWrapper);
} catch (Throwable ex) {
// 省略...
}
return exposedObject;
}
- Spring是通过递归的方式获取目标bean及其所依赖的bean的;
- Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。
3
小结
作者:爱宝贝丶
来源:my.oschina.net/zhangxufeng/blog/3096394
点击「阅读原文」和栈长学更多~
Spring 如何解决循环依赖问题?的更多相关文章
- Spring如何解决循环依赖问题
目录 1. 什么是循环依赖? 2. 怎么检测是否存在循环依赖 3. Spring怎么解决循环依赖 本文主要是分析Spring bean的循环依赖,以及Spring的解决方式. 通过这种解决方式,我们可 ...
- Spring 如何解决循环依赖的问题
Spring 如何解决循环依赖的问题 https://blog.csdn.net/qq_36381855/article/details/79752689 Spring IOC 容器源码分析 - 循环 ...
- 一张图彻底理解Spring如何解决循环依赖!!
写在前面 最近,在看Spring源码,看到Spring解决循环依赖问题的源码时,不得不说,源码写的太烂了.像Spring这种顶级的项目源码,竟然存在着这种xxx的代码.看了几次都有点头大,相信很多小伙 ...
- Spring如何解决循环依赖
一.什么是循环依赖 多个bean之间相互依赖,形成了一个闭环. 比如:A依赖于B.B依赖于c.c依赖于A 通常来说,如果问spring容器内部如何解决循环依赖, 一定是指默认的单例Bean中,属性互相 ...
- Spring中解决循环依赖报错的问题
什么是循环依赖 当一个ClassA依赖于ClassB,然后ClassB又反过来依赖ClassA,这就形成了一个循环依赖: ClassA -> ClassB -> ClassA 原创声明 本 ...
- Spring如何解决循环依赖,你真的懂了?
导读 前几天发表的文章SpringBoot多数据源动态切换和SpringBoot整合多数据源的巨坑中,提到了一个坑就是动态数据源添加@Primary接口就会造成循环依赖异常,如下图: 这个就是典型的构 ...
- Spring如何解决循环依赖?
介绍 先说一下什么是循环依赖,Spring在初始化A的时候需要注入B,而初始化B的时候需要注入A,在Spring启动后这2个Bean都要被初始化完成 Spring的循环依赖有两种场景 构造器的循环依赖 ...
- 彻底理解Spring如何解决循环依赖
Spring bean生命周期 可以简化为以下5步. 1.构建BeanDefinition 2.实例化 Instantiation 3.属性赋值 Populate 4.初始化 Initializati ...
- 【Spring】 Spring如何解决循环依赖的问题?
https://mp.weixin.qq.com/s/FtbzTMxHgzL0G1R2pSlh-A 通常来说,如果问Spring内部如何解决循环依赖,一定是单默认的单例Bean中,属性互相引用的场景. ...
随机推荐
- 阿里云Ubuntu安装LNMP环境之PHP7
在QQ群很多朋友问阿里云服务器怎么安装LNMP环境,怎么把项目放到服务器上面去,在这里,我就从头开始教大家怎么在阿里云服务器安装LNMP环境. 在这之前,我们先要知道什么是LNMP. L: 表示的是L ...
- Python基础之基本数据类型的总结
基本数据类型的总结 1. 按照存储空间的占用分(从低到高) 数字 字符串 集合:无序,即无序存索引相关信息 元组:有序,需要存索引相关信息,不可变 列表:有序,需要存索引相关信息,可变,需要处理数据的 ...
- Equalizing Two Strings
F. Equalizing Two Strings 有几种情况可以直接判定结果: ① 字母对应个数不一样,可直接判NO ② 当不满足①时,如果有一个字母有2个及以上的个数,也可直接判YES ③ 当不满 ...
- 在SUSE LINUX中如何用命令行关闭防火墙?
sudo /sbin/SuSEfirewall2 stop 因为系统重启防火墙会自动开启, 导致ssh远程无法登陆,但系统里是可以PING出.也可以上网. 所以需要永久性关闭系统自带的防火墙,命令如下 ...
- 解决spring-boot 各版本包冲突兼容的方法
思路 在微服务盛行的当下,spring boot 流行程度已经家喻户晓.但同时,随着spring boot 快速迭代,出现了很多版本,比如当前已经推出了2.2.x-SNAPSHOT/ , ...
- Vue之混入(mixin)与全局混入
Vue之混入(mixin)与全局混入 接下来通过一个简单的例子看看混入的基础用法: 首先新建一个mixin.js文件,添加以下代码. let mixin = { data() { return { m ...
- elasticsearch+kibana setup
加载示例数据,设置index的时候出错: 提示 forbidden 则可能是es的问题,需要执行如下命令: curl -XPUT -H "Content-Type: application/ ...
- babel 实践
一.@babel/core var babel = require("@babel/core");babel.transform(code, options, function(e ...
- ant-design-pro中引入bizcharts报错:BizCharts is not defined 解决
解决方法: 在config.js 中的 externals 配置项中进行了如下配置修改: externals: { '@antv/data-set': 'DataSet', // bizcharts: ...
- 使用IEDriverServer.exe驱动IE,实现自动化测试
1. 下载IEDriverServer: https://www.nuget.org/packages?q=IEDriver 2. 解压缩得到IEDriverServer.exe和IEDriverSe ...