spring getBean及循环依赖基本流程分析

从零配置ORB-SLAM3:TUM-VI数据集yaml文件参数调优指南 本文深入解析了ORB-SLAM3在TUM-VI数据集上的yaml配置文件参数调优方法。针对双目惯性模式,详细拆解了相机标定、IMU噪声模型和ORB特征提取三大模块的关键参数,解释了其原理与影响,并通过实战案例展示了如何通过调整特征点数量、FAST阈值及IMU噪声参数,有效提升系统在低纹理环境下的鲁棒性和轨迹精度。 阅读详情

前言

  本文基于大佬 文章并结合个人理解进行了一个简单的流程整理,仅供参考,欢迎交流。

一、Bean的三级缓存及简单bean的实例化过程

  在bean的实例化过程中,spring使用了3个缓存,这3个缓存是互斥的,即其中一个存有bean的缓存则其他2两个便没有。具体定义如下:

/** Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of singleton factories: bean name to ObjectFactory. */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
	
	/** Set of registered singletons, containing the bean names in registration order. */
	private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

  按个人理解,我将singletonObjects称为3级缓存、earlySingletonObjects称为2级缓存、singletonFactories称为1级缓存。后文将按此定义进行描述。当bean被完全实例化后其将被存入三级缓存。源码如下:

protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, singletonObject);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

  当用容器初始化完成后会去对非延迟加载的bean进行注册,刚开始时会尝试从这三个缓存中获取bean的实例。源码如下:

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
								singletonObject = singletonFactory.getObject();
								this.earlySingletonObjects.put(beanName, singletonObject);
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

  如源码所示,其会根据一定的条件依次从3、2、1级缓存中去获取bean。当第一次尝试获取的时候getSingleton(beanName, true)肯定是拿不到bean的,那么它会进入创建bean的流程。在进入bean创建前,还有一个重要步骤就是将这个beanName加入singletonsCurrentlyInCreation供后续getSingleton使用。接着核心流程将会为bean 创建一个1级缓存对象ObjectFactory供后续使用,改2级缓存对象将不会被添加到1级缓存,而是直接使用。源码如下:

// Create bean instance.
				if (mbd.isSingleton()) {
					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;
						}
					});
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

  这里的lamda表达式就是ObjectFactory的匿名实现。接着核心流程将调用这个匿名类——singletonFactory.getObject(),并进入doCreateBean流程,该方法是真正创建bean的地方。在此方法中,首先会创建bean的实例,此时的bean实例的属性还未初始化,还是一个比较原始的bean,然后再为bean创建一个1级缓存对象ObjectFactory并将其添加1级缓存中,这个1级缓存对象在解决循环依赖的时候才会被取出并执行它的getObject方法。源码如下:

// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		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) {
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

  随后便是初始化bean的属性,如果没有循环依赖在后面调用getSingleton(beanName, false)时将还是拿不到bean,也就不会继续后面的循环依赖检测。源码如下:

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);// null
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// true
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {// false
			...
			return null;
if (earlySingletonExposure) {// true
			Object earlySingletonReference = getSingleton(beanName, false); // null
			if (earlySingletonReference != null) {// false 循环依赖检测
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}

  后面便是对bean的实例化完成并进行bean的注册,也即最开始的addSingleton方法。根据个人理解对总的流程进行了如下总结:
在这里插入图片描述

二、循环依赖

  按个人理解spirng能解决循环依赖的巧妙设计在于2阶段的bean实例化和3级缓存。现假设存在A->B,B->A两个对象相互依赖。A定义在前,A实例化后去初始化属性的时候会去找B的实例,接着B又开始实例化,B实例化的时候去找A的引用。如上文所述A初始化时会添加一个1级缓存对象ObjectFactory,这个对象在B初始化时又去获取A的时候就会被获取到并调用getObject方法。这个时候,获取到A的原始版本并被添加到了2级缓存中。B初始化完成后,那么就能被赋值到A的属性中,A的属性被初始化后就进入A初始化后期对循环依赖的检测流程。在对A进行循环依赖检测的时候,会再次调用getSingleton(beanName, false),此时就能拿到2级缓存里面的A,如果A在前面的被initializeBean代理增强过那么循环依赖检测就会抛异常,如果没有则接着后面的流程完成bean的实例化。
循环依赖检测的代码如下:

if (earlySingletonExposure) {// true
			Object earlySingletonReference = getSingleton(beanName, false);// 循环依赖时 2级缓存中取出A
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {// 增强后 false
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {// 增强后抛异常
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

  spring只支持setter注入的singleton循环依赖:1、prototype不是单例不使用三级缓存,只缓存了beanName作为循环依赖判断。2、构造器注入在第一阶段createWrappedInstance时发生,到达不了三级缓存循环依赖的处理的流程。
  发生循环依赖,spring的大致处理流程如下:
在这里插入图片描述

STEP 7-Micro/WIN SMART 编程软件:从入门到精通的使用指南 通过不断实践,熟悉软件的各项功能和操作技巧,工程师可更好地应对工业自动化控制中的各种挑战,开发出高效、稳定的控制程序。项目的基本组件是构成程序的核心元素,包括:程序块(主程序 OB1、子程序和中断程序)、数据块(给 V 存储器赋初值)、系统块(硬件组态和参数设置)、符号表(用符号代替存储器地址,使程序更易理解)以及状态图表(监视、修改和强制变量状态)。下载程序时,单击工具栏上的 “下载” 按钮,在弹出的下载对话框中选择要下载的块(程序块、数据块、系统块),单击 “下载” 即可。 阅读详情

相关推荐

告别CPU空转!用STC8的SPI+DMA高效驱动上百颗WS2812B灯珠

本文详细解析了如何利用STC8单片机的SPI+DMA外设高效驱动WS2812B全彩灯珠,解决传统软件延时驱动方式在长灯带应用中的性能瓶颈。通过硬件方案设计、数据格式转换和DMA传输配置,实现高达400Hz的刷新率和低于5%的CPU占用率,适用于大规模灯光项目。

weixin_30847939的博客 396

Spring源码分析之getBean流程分析(循环依赖)

文章目录前言一、getBean(String beanName)1.1 getSingleton(beanName)1.1.1 三级缓存1.2 单例Bean的创建1.2.1 singletonFactory.getObject()1.2.2 createBeanInstance(beanName, mbd, args)二、循环依赖 前言 当Spring的资源解析器把解析好的bean加载到IOC容器后,我们要向获取某个bean实例,只需getBean(beanName)即可,这篇文章就是分析这个方法的流程,

weixin_43004049的博客 569

HAMi 核心模块与架构设计

HAMi 的架构设计是围绕 Kubernetes 生态系统构建的,通过扩展 Kubernetes 的调度能力和设备管理能力,为用户提供了高效、灵活的异构设备虚拟化和管理解决方案。

北斗云的博客 2552

Spring之循环依赖底层源码解析(二)

Spring之循环依赖底层源码解析 三级缓存 解决循环依赖思路分析 总结 三级缓存总结 反向分析singletonFactories 三级缓存 三级缓存是通用的叫法 一级缓存: singletonObjects singletonObjects中缓存的是已经经历了完整生命周期的Bean对象 二级缓存: earlySingletonObjects earlySingletonObjects比singletonObjects多了一个early,表示缓存的是早期的Bean对象

枫度柚子 1609

CCF201803-2 碰撞的小球 python

一些话:已经不知道是第几次做这道题了(大概第三次吧),真的常做常新,每次都有新的细节想法。虽然方法简单粗暴,但好在方便理解,对于我这种菜鸟选手而言。 但在做的过程中,最开始还忽略了输入的小球初始位置有可能是无序的,输出的时候要保持相对位置。CCF真的考验细节,希望上考场时能够认真仔细一点。就酱… #碰撞的小球 #当小球坐标为0或L时,会朝相反方向移动 #当两个小球坐标相等时,会分别转向相反的方向 #计算t秒之后小球的位置 n,L,t = map(int,input().split()) location .

tanya_dre的博客 350

WinInet 编程:MFC 中的互联网编程

WinInet 是一套 Windows API(应用程序编程接口),用于实现互联网应用程序的网络通信和数据传输。WinInet 抽象了底层网络协议和硬件细节,为程序员提供了一套统一的接口,简化了互联网应用程序的开发过程。WinInet 广泛应用于各种 Windows 应用程序中,包括网页浏览器、下载管理器、网络游戏等。MFC WinInet 是一套强大的类库,为 MFC 程序员提供了在 Windows 平台上实现互联网通信和数据传输的工具。

JAZJD的博客 1637

Spring AOP 动态代理源码解析

(基于spring aop 5.3.1) 前述、spring aop 主要解析类为AnnotationAwareAspectJAutoProxyCreator 主要的动态代理逻辑是在在AbstractAutoProxyCreator类的三个方法中,这三个方法分别是: (1)org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference (2)org.springframework.a

祁东握力的博客 2180

golang 线上事故

golang 线上事故 最近公司要做大促的一些活动。并且单量,qps持续上涨。之前使用的是django python 语言做的一个服务端。目前已经部署的国家里面最多的国家会有300+个实例。大促期间还可能会增加一个实例数。这么多的实例部署,回滚的时间都会特变长,除了问题也不好定位。并且如此多的一个机器,连接数* 实例数也会导致DB等其他服务扛不住这么大的并发。所以决定上go服务解决性能问题。 ...

lcf枫的博客 1537

Spring为什么会出现循环引用异常

从@Aysnc引起的依赖循环报错开始,讲解原理,发生过程,如何解决。更对几种常见的多次代理情形进行讲解

qq_42814833的博客 1505

一文搞懂蚁群算法Ant Colony Optimization(ACO)!!!(灵感起源+数学原理+代码实现+实战应用)

本文系统介绍了蚁群算法的原理与实现。首先从蚂蚁觅食行为出发,阐释了信息素正反馈机制如何引导群体找到最短路径。随后详细解析了算法的数学模型,包括状态转移规则和信息素更新机制。通过MATLAB代码演示了算法在旅行商问题(TSP)中的应用,展示了路径构建和优化的完整流程。最后讨论了算法的优势、局限性和实际应用场景。蚁群算法通过模拟生物智能,为解决复杂优化问题提供了一种高效方法,其核心在于信息素的正反馈机制与随机探索的平衡。

qq_42212808的博客 887

【QT开发教程】QMatrix4x4类详解及实战应用:Qt中的4x4矩阵变换

在计算机图形学和三维图形应用中,矩阵变换是一个核心概念。Qt框架提供了QMatrix4x4类,用于处理4x4矩阵变换,帮助开发者在三维空间中进行复杂的几何计算。本文将深入探讨QMatrix4x4的功能及其在Qt应用中的实际应用。

科技改变人类,技术成就未来 719

Spring5 源码阅读笔记(1.4.2.3)addSingletonFactory(beanName, ()->getEarlyBeanReference(beanName, mbd, bean))

这个方法的入参里有一个匿名类的返回值。 我们先看这个方法的代码: 类 DefaultSingletonBeanRegistry protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singlet...

日有寸进 5023

Python爬虫分析二手交易平台商品定价合理性:基于多维度数据挖掘与机器学习

本文针对二手交易平台商品定价合理性问题,设计并实现了一个基于Python的多技术融合爬虫系统,结合Scrapy框架、Selenium自动化测试工具、Anti-Scraping对抗技术以及机器学习算法,对国内主流二手交易平台(闲鱼、转转等)进行大规模数据采集与分析。系统实现了商品信息的多维度采集、价格合理性模型构建、可视化展示等功能,为二手商品买卖双方提供科学的定价参考。实验结果表明,该系统能够有效识别定价异常商品,准确率达到89.7%,具有较高的实用价值。关键词:Python爬虫;二手交易;定价分析;

2201_76125261的博客 297

筑基期第一式:深入Spring源码之第二节getBean全流程【循环依赖分析+扩展点分析】

这一节是对getBean全流程的源码级别分析,核心内容涉及到了循环依赖的检测和处理以及getBean过程中扩展点的分析已经场景应用,这部分内容的源码非常繁琐复杂,啃下全文得花不少时间,需要耐心点,源码不要跟得太深。看不下去可以看我总结的小结部分

weixin_50675808的博客 530

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

(Spring源码分析)Spring解决循环依赖源码分析

目录一、什么是循环依赖二、循环依赖的Demo三、Spring解决循环依赖的源码分析getBean(beanName)doGetBean(name, null, null, false)getSingleton(beanName)createBean(beanName, mbd, args)doCreateBean(beanName, mbdToUse, args)populateBean(bean...

断橋殘雪的博客 1012

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Spring为什么需要三个级别的缓存来解决循环依赖

首先不是说非要三级缓存机制才能解决循环依赖,一级缓存同样可以解决,把三级缓存代码平铺化就好了嘛,或者使用JVM指令,字节码等技术完成循环依赖,但你想一下,那样的话代码的可读性必然很低。所以第一个原因就是使用三级缓存解决循环依赖使得代码可读性非常好。第二个原因是三级缓存中的工厂,每次getObject方法返回的实例不是同一个对象,所以需要二级缓存来缓存一下三级缓存生成的bean,这样就保证了两个类的属性是环形依赖,不会破坏循环依赖。

weixin_74412978的博客 1920

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

​​​​​​​ 展开说说,Spring Bean IOC、AOP 循环依赖

一、前言 延迟满足能给你带来什么? 大学有四年时间,但几乎所有人都是临近毕业才发现找一份好工作费劲,尤其是我能非常熟悉的软件开发行业,即使是毕业了还需要额外花钱到培训机构,在学一遍编程技术才能出去找工作。好像在校这几年压根就没学到什么! 就我个人而言可能是因为上学期间喜欢编程,也从师哥、师姐那里听到一些关于毕业后找工作的不容易,也了解了一些社会上对程序员开发技能的要求级别。也就是得到了这些消息,又加上自己乐于折腾,我给自己定了一个每天都能完成的小目标: 红尘世界几个王,我自不服迎头上。 日敲代码两

HY1273383167的博客 237

阿里三面:什么是循环依赖?你说一下Spring解决循环依赖的流程

我们使用Spring的时候,在一个对象中注入另一个对象,但是另外的一个对象中也包含该对象。如图:

wdj_yyds的博客 887

Spring5源码阅读--如何解决循环依赖?

首先要明确的是,循环依赖有以下几种: 构造函数的循环依赖。这种依赖显然是解决不了的。 非单例Bean的循环依赖。这种依赖也是解决不了的。 单例Bean的循环依赖。本文介绍的就是如何解决单例Bean的循环依赖的问题。 先来看一下测试代码,为了省略篇幅去掉setter和getter代码://Car.java package beans;public class Car { String name

1808

Spring源码系列:Spring Bean实例化流程(spring是如何解决循环依赖问题的)

spring实例化bean的过程是一个比较复杂的过程,简单的一个getBean方法 内部却做了很多的事情。当然getBean方法也是我们再研究spring源码道路上一个重要的方法。是不可能去绕开的,因为很多spring的扩展接口都是基于getBean方法去展开的。 笔者这次就不去一一 的把源码贴出来 逐行去分析了 因为这样我感觉效果不好。读着读着就不知道自己读到那个类的哪个类的哪个方法了,所以在...

xiaomujiang_dafangzi的博客 835

Spring源码中getBean实例的详细流程

本文主要研究getBean的流程。 1.首先尝试框架会从容器的缓存里获取单例Bean实例,这个单例Bean有可能是一个普通Bean,也有可能是一个FactoryBean,然后调用他的getObject方法返回。 2.如果这里1获取不到,不管是单例还是原型模式,都要框架另外创建实例了。然后进行循环依赖的判断逻辑,正是因为循环依赖,才会用到三级缓存, 3.如果该容器中没有该Bean的BeanDefiniton实例,则递归去父容器去查找。 4.如果该容器中有该Bean的BeanDefiniton实例,则获取B.

Fujie1997的博客 706

getbean方法找不到bean_Spring的bean的加载

这可能是全网分析bean加载流程最详细的文章了,希望对你有所帮助上一篇文章分析了spring读取配置文件的源码,看过之后我相信你对配置文件的加载流程应该有了大概的了解,因为配置文件的解析代码并不复杂,只不过对我们来说比较生疏,因为xml解析平时开发不怎么用,我们没必要了解的太过深入,因为那并不是我们要了解的重点,真正的重点就从现在开始,那就是bean的加载。今天要分析的代码是测试类的第1...

weixin_39895486的博客 3145

Spring核心源码学习笔记-02-getBean

@[TOC](Spring源码解析———获取bean getBean )

LeeYan9的博客 246

Spring IoC 源码导读

源码记录:spring-framework-5.1.7-source-code-read 文章导读 Spring IoC 源码系列(一)BeanDefinition 初始化与注册 Spring IoC 源码系列(二)IoC 容器启动流程分析 Spring IoC 源码系列(三)Spring 事件发布机制原理分析 Spring IoC 源码系列(四)bean创建流程与循环依赖问题分析 Spring...

点滴记录 723

【spring源码】八、循环依赖(重要)

getBean 流程: doGetBean getSingleton1 singletionObject.get(beanName);有则直接返回 earlySingletonObjects.get(beanName);有则直接返回 singletonFactories.get(beanName);没有就直接返回 singletonFactories.get(beanName);获取到了工厂 singletonObject=singletonFactory.getObject(); earlySing

努力充实,远方可期 840

Spring 5 AbstractBeanFactory -- getBean() 源码分析(一)

AbstractBeanFactory#getBean() 方法实现是交给 doGetBean() 方法具体实现的 @Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } @Override public <T> T getBean(String name, Class<T> requiredType

qq_30321211的博客 226
上一篇: ThreadPoolExecutor简单原理流程
下一篇: 基于ReentrantReadWriteLock的读写锁应用及简要原理分析
kongkong000111
博客等级 码龄10年 43粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值