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

上一篇我们在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 = falseif (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是第一次过来,默认是falsenewSingleton = 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对应的单例beansingletonObject = 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*/@Overrideprotected 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.mzph.cn/web/44301.shtml

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

相关文章

计算器原生js

目录 1.HTML 2.CSS 2.JS 4.资源 5.运行截图 6.下载连接 7.注意事项 1.HTML <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-s…

【C++】引用变量详解

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

文档去重(TF-IDF,MinHash, SimHash)

2个doc有些相似有些不相似&#xff0c;如何衡量这个相似度&#xff1b; 直接用Jaccard距离&#xff0c;计算量太大 TF-IDF: TF*IDF TF&#xff1a;该词在该文档中的出现次数&#xff0c; IDF&#xff1a;该词在所有文档中的多少个文档出现是DF&#xff0c;lg(N/(1DF)) MinHash …

基于JAVA+SpringBoot+Vue+Uni-app前后端分离的校园好物小红书分享平台小程序

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 在快速数字化的时代背…

etcd 实现分布式锁

10 基于 Etcd 的分布式锁实现原理及方案

如何通过兔子和窝窝的故事理解“在机器人学习和研究中的获得成本与维护成本”(节选)

获得成本 掌握一门课程&#xff0c;以最为简单的学校成绩过60为例&#xff0c;需要按要求提交材料&#xff0c;包括作业、报告、实验和考试等&#xff0c;依据学分和考核要求的不同&#xff0c;需要对于花费时间和经历进行完成。 维护成本 考完了&#xff0c;如果被动学习那…

docker拉取镜像-配置阿里云镜像加速

1、配置阿里云镜像&#xff08;用于拉取镜像加速&#xff09; sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo syst…

Docker 使用基础(4)—存储卷

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;秒針を噛む—ずっと真夜中でいいのに。 0:34━━━━━━️&#x1f49f;──────── 4:20 &#x1f504; ◀️ ⏸ …

ArcGIS如何快速对齐两个图层

1、问题 如何让两个图层快速对齐 2、使用捕捉工具 移动点或折点&#xff0c;使其与其他要素的折点、边或端点精确重合。 可指定捕捉规则来控制是将输入折点捕捉到指定距离范围内的最近折点、边还是端点。

MySQL数字相关数据处理函数

目录 1. 随机数生成 rand ( ) 2. 四舍五入 round&#xff08;&#xff09; 3. 舍去 truncate ( ) 4. 向上/下取整 5. 空处理 ifnull&#xff08; x , y &#xff09; 1. 随机数生成 rand ( ) rand ( ) 生成 0 到 1 的随机数&#xff1b; rand ( x ) 生成 0 到 1 的随机数…

403 禁止错误: 它是什么?如何修复?

您应该对403错误代码很熟悉&#xff01;这种错误会导致流量损失&#xff0c;甚至错失一些商业机会&#xff01; 什么&#xff1f;您在自己的网站上遇到了403错误&#xff1f;请立即修复它&#xff01;但是什么原因导致这种错误&#xff1f;该如何解决&#xff1f;这两个问题都…

66种智能优化算法和改进优化算法优化BP神经网络【开源代码!】【文末福利IT学习资料】

前言 熟话说得好&#xff0c;创新点不够&#xff0c;智能优化算法来凑&#xff0c;不要觉得羞耻&#xff0c;因为不仅我们这么干&#xff0c;很多外国人也这么干&#xff01;因为创新点实在太难想了&#xff0c;和优化算法结合下是最简单的创新点了&#xff01; 之前给大家分享…

spark shuffle写操作——SortShuffleWriter

写入的简单流程&#xff1a; 1.生成ExternalSorter对象 2.将消息都是插入ExternalSorter对象中 3.获取到mapOutputWriter&#xff0c;将中间产生的临时文件合并到一个临时文件 4.生成最后的data文件和index文件 可以看到写入的重点类是ExternalSorter对象 ExternalSorter 基…

人工智能算法工程师(中级)课程1-Opencv视觉处理之基本操作与代码详解

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师(中级)课程1-Opencv视觉处理之基本操作与代码详解。OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它提供了各种视觉处理函数&am…

Redis为什么变慢了?一文讲透如何排查Redis性能问题

Redis 作为优秀的内存数据库&#xff0c;其拥有非常高的性能&#xff0c;单个实例的 OPS 能够达到 10W 左右。但也正因此如此&#xff0c;当我们在使用 Redis 时&#xff0c;如果发现操作延迟变大的情况&#xff0c;就会与我们的预期不符。 你也许或多或少地&#xff0c;也遇到…

以太网中的各种帧结构

帧结构&#xff08;Ethernet Frame Structure&#xff09;介绍 以太网信号帧结构&#xff08;Ethernet Signal Frame Structure&#xff09;&#xff0c;有被称为以太网帧结构&#xff0c;一般可以分为两类 —— 数据帧和管理帧。 按照 IEEE 802.3&#xff0c;ISO/IEC8803-3 …

短视频矩阵管理系统:如何提升内容质量,帮助企业获客?

在数字化营销蓬勃发展的今天&#xff0c;短视频已成为企业推广的重要阵地。然而&#xff0c;如何高效管理短视频内容&#xff0c;提升内容质量&#xff0c;进而帮助企业精准获客&#xff0c;成为企业亟待解决的问题。短视频矩阵管理系统应运而生&#xff0c;以其强大的功能和灵…

编程范式之并发编程

目录 前言1. 并发编程的定义2. 并发编程的特点2.1 任务交替执行2.2 状态共享与同步2.3 并行执行 3. 并发编程的适用场景3.1 高性能计算3.2 I/O 密集型应用3.3 实时系统 4. 并发编程的优点4.1 提高资源利用率4.2 缩短响应时间4.3 提高系统吞吐量 5. 并发编程的缺点5.1 编程复杂性…

硬盘模式vmd怎么改ahci_电脑vmd改ahci模式详细步骤

最近有很多网友问&#xff0c;我新买的电脑安装原版win10或win11找不到驱动器呀&#xff0c;进入第三方pe又找不到硬盘&#xff0c;找到硬盘安装后又出现安装蓝屏的情况&#xff0c;新机器怎么回事呀&#xff1f;这位网友内心有点崩溃&#xff0c;不知道啥原因。其实这些都是由…

初识c++(类与对象——上)

一、类的定义 1、类定义格式 • class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后面分号不能省 略。类体中内容称为类的成员&#xff1a;类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或 者成员函…