Spring源码十九:Bean实例化流程二

news2024/9/20 19:35:35

上一篇我们在Spring源码十八:Bean实例化流程一 中,主要讨论了Spring在实例化前的两重要准备工作,1、获取我们前面注册好的BeanDefinition,将GenericBeanDefinition封装为RootBeanDefinition如果Bean Definition只存在父容器中,还会进行合并操作,然后做了严谨的异常判断处理。2、如果bean配置了依赖的bean的名称,还会检查下配置的依赖,是否已经处于bean依赖的引用链上了,如果没有处于bean依赖引用链上,就会提前来实例化bean依赖的那些bean。最后找到实例化的入口。

 今天我们开始分析下单例bean是如何创建:咱们接着上一篇代码往下看

getSingleton

再进入代码中看下逻辑:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			// 从单例缓存中获取Bean的实例
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				// 如果当前bean正在销毁标志为true,则抛出异常。 默认:singletonsCurrentlyInDestruction = false
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				// 将当前beanName放入singletonsCurrentlyInCreation列表中,标志当前bean正在被创建
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// !!!!  调用简单工厂方法来实例化bean  !!!! //
					singletonObject = singletonFactory.getObject();
					// 标志当前bean是第一次过来,默认是false
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					// 再努力一次,如果通过简单工厂创建失败: 尝试从单例缓存中,获取beanName对应的单例bean
					singletonObject = this.singletonObjects.get(beanName);
					// 缓存里还是没有,此时再将异常抛出
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					// 从singletonsCurrentlyInCreation列表中移出,标志当前beanName对应的bean已经创建完成了。
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					// 看到了嘛,看到了嘛,第一次标志在这里用的,单例缓存入的地方也再这里,哈哈 我们找到啦
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

这段代码是Spring框架中用于创建和获取单例bean实例的一部分。以下是对这段代码的分析:

  1. 使用lambda表达式:代码中使用了Java 8的lambda表达式来创建一个匿名的 ObjectFactory 实例。这个 ObjectFactory 会在需要时调用其 getObject() 方法来创建bean。

  2. getSingleton()方法getSingleton(beanName, singletonFactory) 方法被调用来获取名为 beanName 的单例bean。如果这个bean尚未被创建,singletonFactory.getObject() 将被调用以创建它。

  3. createBean()方法:在lambda表达式中,如果bean不存在,将调用 createBean(beanName, mbd, args) 方法来创建bean。这个方法负责完整的bean创建过程,包括依赖注入、初始化等步骤。

  4. 异常处理:如果在创建bean的过程中抛出了 BeansException(例如,由于循环依赖或其他bean创建问题),代码将执行以下操作:

    • 调用 destroySingleton(beanName) 来从单例缓存中移除部分创建的bean实例。这是必要的,因为创建过程中可能会因为解决循环依赖而提前将bean放入缓存。
    • 抛出原始的 BeansException,以通知调用者bean创建失败。
  5. 获取bean实例:如果bean成功创建,sharedInstance 将包含新创建的bean实例。然后,调用 getObjectForBeanInstance(sharedInstance, name, beanName, mbd) 方法来获取bean实例对象。这个方法可能执行额外的处理,比如应用 FactoryBean 的逻辑或处理bean的后置处理(post-processing)。

  6. 单例缓存:整个过程中,Spring使用 singletonObjects 作为缓存来存储已经创建的单例bean。这样,后续请求相同bean时可以直接从缓存中获取,而不需要重新创建。

这段代码体现了Spring框架中创建单例bean的复杂性,包括异常安全、延迟初始化和对循环依赖的处理。通过使用 ObjectFactory 和lambda表达式,Spring能够以一种灵活且高效的方式来管理bean的生命周期。

createBean

上面我已经找到真正创建bean的地方,也看到Spring是通过简单工厂创建实例的也验证了人命常说的bean工厂、工厂模式。同时也看到单例bean首次创建,会放入单例缓存池中。但是整个方法有个内部类,当然这里是Java8的函数式接口实现的,咱们跳出来看下这个默认方法是做了什么逻辑处理。通过这个方法来

看到上图标注的地方createBean见名知意,应该是这个方法包含了实例化的核心逻辑,咱们进入方法内部一探究竟之前简单分析一下:在这个内部类里首先会通过createBean来实例化一个bena,如果实例化的过程中出现了异常,就会调用方法destroy Singleton方法,来清除单利bean相关的一系列缓存信息。

/**
	 * Central method of this class: creates a bean instance, 创建bean实例对象
	 * populates the bean instance, applies post-processors, etc. 填充bean实例、应用后置处理器
	 * @see #doCreateBean
	 */
	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.    判断需要创建的bean是否可以实例化、是否可以通过当前类加载器加载
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides. 	准备bean中的方法覆盖
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.  给BeanPostProcessors一个返回代理而不是目标bean实例的机会。
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse); // 如果bean配置类后置处理器PostProcessor,则这里返回一个proxy代理对象
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args); // bean实例对象创建方法
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

 

总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1923205.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“好物”推荐+Xshell连接实例+使用Conda创建独立的Python环境

目录 主题&#xff1a;好易智算平台推荐RTX 4090DGPU实例租用演示安装配置torch1.9.1cuda11.1.1环境引言&#xff1a;算力的新时代平台介绍&#xff1a;技术与信任的结晶使用案例&#xff1a;实际使用展示创建实例开始使用连接实例&#xff08;下文演示使用Xshell连接&#xff…

阿里云ECS服务器安装jdk并运行jar包,访问成功详解

安装 OpenJDK 8 使用 yum 包管理器安装 OpenJDK 8 sudo yum install -y java-1.8.0-openjdk-devel 验证安装 安装完成后&#xff0c;验证 JDK 是否安装成功&#xff1a; java -version设置 JAVA_HOME 环境变量&#xff1a; 为了确保系统中的其他应用程序可以找到 JDK&…

智能优化算法之蚁群算法ACO

蚁群算法&#xff08;Ant Colony Optimization, ACO&#xff09;由意大利学者马尔科多里戈&#xff08;Marco Dorigo&#xff09;于1992年在其博士论文中首次提出。灵感来自于自然界中的蚂蚁群体行为&#xff0c;特别是蚂蚁在寻找食物过程中所展示的路径优化能力。蚁群算法属于…

Snap Video:用于文本到视频合成的扩展时空变换器

图像生成模型的质量和多功能性的显著提升&#xff0c;研究界开始将其应用于视频生成领域。但是视频内容高度冗余&#xff0c;直接将图像模型技术应用于视频生成可能会降低运动的保真度和视觉质量&#xff0c;并影响可扩展性。来自 Snap 的研究团队及其合作者提出了 "Snap …

JAVA从入门到精通之入门初阶(二)

1. 自动类型转换 自动类型转换&#xff1a;类型范围小的变量可以赋值给类型范围大的变量 byte->int public class java_7_10 {public static void main(String[] args) {//自动类型转换//类型范围小的变量可以赋值给类型范围大的变量 byte->intbyte a 12;int b a;//自动…

MT6985(天玑9200)芯片性能参数_MTK联发科旗舰5G移动平台处理器

MT6985天玑 9200 旗舰移动平台拥有专业级影像、沉浸式游戏和先进移动显示技术&#xff0c;以及更快捷、覆盖更广的 5G 和 支持 Wi-Fi 7 连接&#xff0c;具有高性能、高能效、低功耗表现。率先采用 Armv9 性能核&#xff0c;全部支持纯 64 位应用&#xff0c;开启高能效架构设计…

华为OD机试 - 堆内存申请(Java 2024 D卷 100分)

华为OD机试 2024D卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;D卷C卷A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测…

nginx正向代理和反向代理

nginx正向代理和反向代理 正向代理以及缓存配置 代理&#xff1a;客户端不再是直接访问服务器&#xff0c;通过代理服务器访问服务端。 正向代理&#xff1a;面向客户端&#xff0c;我们通过代理服务器的IP地址访问目标服务端。 服务端只知道代理服务器的地址&#xff0c;真…

【RHCE】基于密钥的身份验证(Win-Linux)

目的&#xff1a;要提⾼系统安全性&#xff0c;通过在 OpenSSH 服务器上禁⽤密码⾝份验证来强制进⾏基于密钥的⾝份验证。 1、一台虚拟机无需密码连接另一台虚拟机 .ssh目录 > 保存了ssh相关的key和一些记录文件 &#xff08;1&#xff09;生成密钥对 使⽤这个流程在本地…

智慧港口可视化:提高运营效率与安全性

智慧港口通过图扑可视化技术&#xff0c;实时展示船舶停泊、货物装卸等关键数据&#xff0c;提高运营效率&#xff0c;保障港口的整体安全性与可靠性。

IT资产管理专题丨一文读懂什么是企业IT资产管理系统

在现代企业管理中&#xff0c;IT资产的管理变得越来越重要。随着信息技术的飞速发展&#xff0c;企业IT资产种类繁多&#xff0c;包括硬件设备、软件应用、许可证、合同等。 如何有效管理和利用这些资产成为企业面临的一大挑战。本文将通过人物对话的形式&#xff0c;详细解读企…

离线语音识别芯片在智能生活中的应用

离线语音识别芯片&#xff0c;这一技术正逐渐渗透到我们日常生活的每一个角落&#xff0c;为众多产品带来前所未有的智能体验。它能够应用到多种产品中&#xff0c;‌包括但不限于&#xff1a;‌ 1、智能音箱&#xff1a;‌语音识别芯片作为智能音箱的核心&#xff0c;‌使用户…

中霖教育:2024年中级经济师备考还来得及吗?

【中霖教育怎么样】【中霖教育口碑】 2024年的中级经济师考试还未开始报名&#xff0c;考试时间在11月16日-11月17日进行&#xff0c;考生目前距离考试还有半年的准备时间。不同的考生人群针对性的复习方法不同&#xff0c;以下内容可以作为大家的参考。 1、零基础考生&#…

【MySQL系列】VARCHAR的底层存储

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

MSPM0G3507(三十六)——超声波PID控制小车固定距离

效果图&#xff1a; 波形图软件是VOFA&#xff0c;B站有教程 &#xff0c;虽然有缺点但是非常简单。 视频效果&#xff1a; PID控制距离 之前发过只有超声波测距的代码&#xff0c;MSPM0G3507&#xff08;三十二&#xff09;——超声波模块移植代码-CSDN博客 SYSCFG配置&#…

Nacos服务公网环境登陆报密码错误问题排查

作者&#xff1a;小丫 一、问题现象 nacos服务内网可以正常登录&#xff0c;如下&#xff1a; 走公网代理出来之后&#xff0c;无法正常登录&#xff0c;报错"用户名密码错误" 二、排查步骤 1、链路分析 首先确认公网代理的链路&#xff1a; 域名—>haprox…

扩散的魔法:如何打造未来生物打印?

生物打印技术正在快速发展&#xff0c;它允许我们将生物材料、细胞和生长因子等生物活性成分精确地打印成具有特定形状和功能的结构。而扩散现象在生物打印中扮演着至关重要的角色&#xff0c;它影响着打印结构的特性、机械性能、生物功能和形态。为了更好地利用扩散现象&#…

青年发展型城市成新青择地,期待与挑战并存

随着社会的发展和城市化进程的加快&#xff0c;青年人在选择未来定居地时面临着越来越多的选择。近日&#xff0c;中国青年报社社会调查中心联合问卷网对1500名青年进行的一项调查显示&#xff0c;74.8%的受访青年表示会优先考虑青年发展型城市。那么&#xff0c;青年在选择未来…

深耕一个领域存在的风险?

深耕一个领域存在的风险? 我们常常听到:要深耕一个领域/行业。 对于个人来说是选择一份职业深耕,还是在多个领域尝试? ​ 首先看看人才分类 人才的分类可以归纳为三种类型,I型,T型,X型,三种类型简称ITX “I” 型人才 “I” 型人才可以分为专才或者通才。横向放置…

文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《面向规模化分布式可再生能源并网的群网协同互动优化方法》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…