当前位置: 首页 > article >正文

Spring源码浅析の循环依赖

AbstractBeanFactory#doGetBean:尝试获取bean

如果bean是单例的:

if (mbd.isSingleton()) {
	//尝试获取bean <一>
	sharedInstance = getSingleton(beanName, () -> {
		try {
			//获取不到就创建
			return createBean(beanName, mbd, args);
		}
		catch (BeansException ex) {
			// Explicitly remove instance from singleton cache: It might have been put there
			// eagerly by the creation process, to allow for circular reference resolution.
			// Also remove any beans that received a temporary reference to the bean.
			destroySingleton(beanName);
			throw ex;
		}
	});
	//然后再次获取
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	
	...	
}

<一>
DefaultSingletonBeanRegistry#getSingleton 方法
先从单例池中获取:Object singletonObject = this.singletonObjects.get(beanName);
如果获取不到就去创建一个:singletonObject = singletonFactory.getObject(); 实际调用的是AbstractBeanFactory#createBean <二>
然后放入单例池 addSingleton(beanName, singletonObject);

<二>
重点是 Object beanInstance = doCreateBean(beanName, mbdToUse, args);

AbstractAutowireCapableBeanFactory#doCreateBean的逻辑:

  • 实例化对象:AbstractAutowireCapableBeanFactory#createBeanInstance
  • 解决循环依赖:
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
		isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
	if (logger.isTraceEnabled()) {
		logger.trace("Eagerly caching bean '" + beanName +
				"' to allow for resolving potential circular references");
	}
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));<>
}

<三>

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		锁单例池,防止并发
		synchronized (this.singletonObjects) {
			单例池中找不到当前bean
			if (!this.singletonObjects.containsKey(beanName)) {
				在三级缓存中放入 k:当前bean名称 value 工厂
				this.singletonFactories.put(beanName, singletonFactory);
				二级缓存删除当前bean的名称
				this.earlySingletonObjects.remove(beanName);
				保存当前已经注册单例bean的名称
				this.registeredSingletons.add(beanName);
			}
		}
	}
  • 属性赋值:AbstractAutowireCapableBeanFactory#populateBean
  • 初始化:AbstractAutowireCapableBeanFactory#initializeBean

循环依赖:A和B两个实例,A的属性是B,B的属性是A
前提条件,A和B都是单例的。假设目前要初始化A:
1、AbstractBeanFactory#doGetBean 尝试获取A
2、获取不到,AbstractBeanFactory#createBean 创建A
 2.1、实例化A
 2.2、解决循环依赖:在三级缓存中放入k:a,V:A的工厂
 2.3、设置属性,发现需要B
  2.3.1、AbstractBeanFactory#doGetBean 尝试获取B
  2.3.2、获取不到,AbstractBeanFactory#createBean 创建B
   2.3.2.1、实例化B
   2.3.2.2、解决循环依赖:在三级缓存中放入k:b,V:B的工厂
   2.3.2.3、设置属性,发现需要A,再次调用AbstractBeanFactory#doGetBean(在AbstractAutowireCapableBeanFactory#autowireByNamegetBean) ,走Object sharedInstance = getSingleton(beanName);<四>
   2.3.2.4、初始化B,DefaultSingletonBeanRegistry#addSingleton 中将B放入一级缓存,删除二级缓存
 2.4、初始化A,DefaultSingletonBeanRegistry#addSingleton 中将A放入一级缓存,删除二级缓存

<四>

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	Object singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				//根据bean的名称找到bean工厂
				if (singletonFactory != null) {
					//创建bean
					singletonObject = singletonFactory.getObject();
					//放入二级缓存
					this.earlySingletonObjects.put(beanName, singletonObject);
					//从三级缓存中清除
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	//返回bean的实例
	return singletonObject;
}

小结

doGetBean中有两个getSingleton方法,第一个用于解决依赖循环问题,第二个只有一级缓存中没有对应bean的时候,才会调用createBean,实例化,向三级缓存中提前曝光。属性设置,初始化都是在createBean中的


http://www.kler.cn/a/287676.html

相关文章:

  • shell脚本配置nginx
  • 麒麟V10,arm64,离线安装docker和docker-compose
  • 【计算机网络】协议定制
  • C++之内存管理
  • Flume 单机与集群部署详细教程
  • 什么是SSL VPN?其中的协议结构是怎样的?
  • 泰山派的小手机后续(2)
  • upload-labs通关攻略
  • Clickhouse集群化(四)使用clickhouse-operator部署clickhouse集群
  • vs中在工具箱添加自定义控件numberTextBox
  • 链表题总结
  • 使用MySql
  • [YM]课设-C#-WebApi-Vue-员工管理系统 (六)前后端交互
  • 二手电脑配置给你不一样的成就感之四
  • SQLite3 数据类型深入全面讲解
  • B3918 [语言月赛 202401] 图像变换
  • 力扣375.猜数字大小 II
  • AI时代,需要什么样的服务器操作系统?
  • 51单片机-定时器时钟
  • docker实战基础五(Dockerfile)
  • 2024年【电气试验】新版试题及电气试验证考试
  • 请解释Java中的装箱拆箱操作对性能的影响,并讨论其最佳实践。什么是Java中的值传递和引用传递?它们在函数调用中的表现有何不同?
  • redis主从+高可用切换+负载均衡
  • react 列表页面中管理接口请求的参数
  • 当前开发技术的未来发展:趋势、机遇与挑战
  • Spring Cloud Stream与Kafka(一)