Spring框架系列之bean的生命周期底层原理07

2023-05-16

上一篇我们预留了两个大的内容,一个是Object sharedInstance = getSingleton(beanName)从单例池中获取数据,另外一个是getSingleton方法创建单例Bean,如下图:

getSingleton(beanName, () -> {
   try {
         return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
      destroySingleton(beanName);
      throw ex;
   }
});

本篇我们就来聊聊上面这个getSingleton方法。

说句掏心窝子的话,要想把Bean的生命周期讲清楚真不是一件容易的事情,要让看官看明白就更难了,所以笔者一直在考虑怎么样才能将Bean的生命周期讲清楚,这里举个实际的案例来讲可能会更明了,后续我们所有的分析也将基于这个案例进行:

有三个类,代码如下:

public class ClassA{
   ClassB classB;
}
public class ClassB{
   ClassA classA;
}
public class ClassC{
   ClassA classA;
}

如上,ClassA依赖ClassB,ClassB依赖ClassA,ClassC也依赖ClassA,我们getBean("classA")来获取ClassA的实例对象,进入到getSingleton这个方法,我们可以看到getSingleton的第二个参数是lambda表达式,进入getSingleton方法:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   synchronized (this.singletonObjects) {
     //关键点一
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         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 + "'");
         }
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
           //关键点二
            singletonObject = singletonFactory.getObject();  // createBean()
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            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;
            }
           //关键点三
            afterSingletonCreation(beanName);
         }

         if (newSingleton) {
           //关键点四
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

关键点一

该方法首先判断singletonObjects单例池中是否有实例,没有则调用beforeSingletonCreation方法将beanName添加到
singletonsCurrentlyInCreation集合中,表示正在创建该单例对象。

关键点二

执行
singletonFactory.getObject()方法,我们上面说过singletonFactory这个对象是一个lambda表达式,那么执行singletonFactory.getObject(),就会实际执行表达式的内容,也就是调用createBean方法。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   ......
   try {
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);  
      if (bean != null) {
         return bean;
      }
   }
   ......
   try {
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
         logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
   ......
}

如上
resolveBeforeInstantiation这个方法是干嘛的呢?如果英语好应该很容易理解,表示在实例化之前做点什么事情,方法里面调用了applyBeanPostProcessorsBeforeInstantiation方法:

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
         if (result != null) {
            return result;
         }
      }
   }
   return null;
}


applyBeanPostProcessorsBeforeInstantiation方法则是循环调用所有InstantiationAwareBeanPostProcessor类型的Bean的后置处理器的postProcessBeforeInstantiation方法,默认情况下只有ConfigurationClassPostProcessor属于InstantiationAwareBeanPostProcessor类型,它直接返回Null,那Spring加这个方法放这里有啥用?用处当然有,Spring通过这种方式给咱们提供了一个扩展点,咱们可以自己定义InstantiationAwareBeanPostProcessor的实现类,来直接返回实例对象,如果这里返回的是非空的对象,则Spring直接返回给咱们了,这样就可以跳过Spring的生命周期流程了。

当然如果经过“实例化之前“这个骚操作得到的是空对象,则会调用doCreateBean来创建实例,这里是核心了,具体放下一篇幅分析。

关键点三

调用afterSingletonCreation方法,将刚刚正在创建的beanName从
singletonsCurrentlyInCreation中移除。

关键点四

调用addSingleton方法将创建好的单例bean添加到单例池singletonObjects中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring框架系列之bean的生命周期底层原理07 的相关文章

  • 基于C++11实现的阻塞队列(BlockQueue)

    思路 xff1a 生产者消费者模型 如图 xff0c 多个生产者线程和多个消费者线程共享同一固定大小的缓冲区 xff0c 它们的生产和消费符合以下规则 xff1a 生产者不会在缓冲区满的时候继续向缓冲区放入数据 xff0c 而消费者也不会在
  • 航空订票系统设计(java、数据库、通信联合项目)

    航空订票系统设计 xff08 java 数据库 通信联合项目 xff09 最近帮高中同学做的一个学校项目 xff0c 这个项目主要是用Java写的 前期主要搭建五个类 xff0c Order xff08 选择 xff09 Passenger
  • java基础之IO流中的字节流

    目录 一 xff1a 字节流写数据 二 xff1a 字节流写数据的方式 三 xff1a 字节流写数据实例 字节流写数据步骤 字节流写数据例子 字节流追加写数据 四 xff1a 字节流读取数据 五 xff1a 字节读取数据的方法 六 xff1
  • java基础之转换流

    目录 一 xff1a 解释 二 xff1a 转换流输入流 1 xff1a 构造方法 2 xff1a InputStreamReader读数据方法 3 xff1a 例子 3 xff1a 注意 三 转换流输出流 1 xff1a 构造方法 2 x
  • java基础之多线程的引入

    目录 一 xff1a 多线程概述 进程 线程 举例 二 xff1a 并行与并发 三 xff1a Java程序的运行原理 四 xff1a JVM启动的时候是单线程还是多线程呢 xff1f 一 xff1a 多线程概述 进程 正在运行的程序 xf
  • 电信运营商云计算体系架构分析

    电信运营商云计算体系架构分析 作者 xff1a 成晓旭 xff08 版权保留 欢迎转载 xff09 第三篇 xff1a 体系架构分析 电信运营商云计算发展分析之一 xff1a 战略定位分析 xff0c 可供参考 电信运营商云计算发展分析之二
  • java基础之线程安全问题(一)

    目录 一 xff1a 线程安全判断依据 二 xff1a 解决线程安全问题实现 同步代码块 1 格式 2 同步代码块的锁对象是谁 xff1f 3 xff1a 同步方法的时候 xff0c 锁对象又是谁呢 xff1f 4 xff1a 静态同步方法
  • java基础之线程安全问题(二)

    目录 一 xff1a Lock锁的使用 xff08 解决同步问题 xff09 二 xff1a 例子 三 xff1a 同步的特点 xff08 1 xff09 同步的前提 xff08 2 xff09 同步的好处 xff08 3 xff09 同步
  • redis基础知识

    目录 一 xff1a 概念 二 xff1a NoSQL分类 三 xff1a Redis数据模型 四 xff1a 键Key 一 xff1a 概念 开源的 xff08 BSD协议 xff09 xff0c 使用ANSI C 编写 xff0c 基于
  • Hive建表以及导入数据

    目录 一 xff1a 内部表和外部表 1 xff1a 外部表 2 xff1a 外部表 3 xff1a 外部表和内部表区别 二 xff1a 上传数据方式 一 xff1a 内部表和外部表 1 xff1a 外部表 内部表基础建表语句一 默认指定文
  • Hive行列互转

    目录 一 xff1a 行转列 1 xff1a lateral view 行转列 2 xff1a explode函数 3 xff1a 例子 二 xff1a 列转行 1 概念 2 xff1a 例子 一 xff1a 行转列 1 xff1a lat
  • Hive行转列的应用之计算公司累加收入

    公司代码 年度 1月 12月的收入金额 burk year tsl01 tsl02 tsl03 tsl04 tsl05 tsl06 tsl07 tsl08 tsl09 tsl10 tsl11 tsl12 853101 2010 100200
  • Hive的常用函数

    目录 1 关系运算 2 数值计算 3 条件函数 4 日期函数 5 xff1a 字符串函数 6 xff1a Hive 中的wordCount 1 关系运算 等值比较 61 61 61 lt 61 gt 不等值比较 61 lt gt 区间比较
  • IDEA配置spring环境,并简单测试

    目录 一 下载安装需要的依赖包 二 IDEA的部署 一 下载安装需要的依赖包 首先 xff0c 我们需要下载一点jar包 第一个jar包是第三方依赖的jar包 xff0c Spring的核心容器依赖commons logging的JAR包
  • Unity导出工作台(Console)数据

    首先在Unity中添加C 脚本 xff1a using System Collections using System Collections Generic using UnityEngine using UnityEditor usin
  • Unity利用代码生成空心立方体(立方体挖走一个圆柱)

    先看效果 还未生成mesh时挖去圆柱的立方体 生成mesh后挖去圆柱的立方体 放代码为敬 xff08 脚本挂在空物体上即可 xff09 xff1a using System Collections using System Collecti
  • 企业ERP系统开发总结及建议

    企业ERP系统开发总结及建议 作者 xff1a 成晓旭 对于像我们这种规模的大型公司 xff0c 自己建设 实施和维护满足公司特定管理要求的管理信息系统 xff0c 是目前部分大型公司建设企业ERP 的常见思路 比如 xff1a XXXX
  • Unity 3D导入txt文本文件坐标并打印

    先看打印结果 xff1a 首先我们创建一个txt文件 xff0c 将坐标输入或复制进去 xff0c 从左到右依次为x y z xff0c 中间用逗号 xff08 英文逗号 xff09 隔开 在Unity工程文件下的Assets文件夹下创建R
  • 2022研究生数学建模竞赛(华为杯)B题

    题目 xff1a 方形件组批优化问题 一 背景介绍 智能制造被 中国制造 2025 列为主攻方向 而个性化定制 更短的产品及系统生命周期 互联互通的服务模式等成为目前企业在智能制造转型中的主要竞争点 以离散行业中的产品为例 xff0c 如电
  • 2022研究生数学建模B题思路

    子问题1 xff1a 排样优化问题 要求建立混合整数规划模型 xff0c 在满足生产订单需求和相关约束条件下 xff0c 尽可能减少板材用量 约束 1 在相同栈 stack xff09 里的产品项 item xff09 的宽度 xff08

随机推荐

  • 找到并标记Mesh顶点

    1 在Unity 3D中新建一个物体 本文以Cube为例 2 创建一个C 脚本 命名为MeshTest 3 在脚本中写入程序 在打开的脚本 MeshTest 上编写代码 xff0c 首先获取 MeshFilter 组件 xff0c 然后获取
  • TCP服务器端、客户端通讯(赋源码)

    实现通讯 xff0c 我们首先要知道是怎么样的一个流程 xff0c 下图是我画的一个通讯流程图 xff1a 一 Linux服务器端 我是在Ubuntu20 04下进行的 xff0c 使用的是C 43 43 xff0c 引入头文件socket
  • win11 命令 wmic:无效的指令 解决办法

    我想你肯定看到过让你修改环境变量的方法 但是 xff0c 如果你的电脑就根本没有装wmic xff0c 再怎么修改环境变量也是徒劳 我们打开设置 xff1a Win 43 I 点击应用 选择 可选功能 添加可选功能 搜索wmic xff0c
  • Python面向对象编程:关于类的方法中属性是否加前缀self的问题

    问题的缘起 今天完成了LeetCode首秀 xff08 而且是用刚学不久的python做的 xff09 xff0c 心情挺激动的 xff0c 毕竟之前只涉猎了竞赛OJ xff0c 没有在应用型平台上刷过题 xff0c 不妨定一个小目标 xf
  • 概念物理Ⅱ 第一讲:绪论

    目录 物理学研究的对象和动机为什么要研究物理学 xff1f 1 满足人类对大自然基本规律的好奇心2 改进技术 发展生产 两个动机之间的关系 物理学的发展历史起源于古希腊古典物理学时间 xff1a 牛顿时代 1900年经典力学 xff08 牛
  • Machine Learning:k近邻算法(KNN)

    目录 写在前面的话k 近邻算法概述优点缺点适用数据范围 原理Python代码实现Sklearn直接调用weights选项algorithm选项 算法测试与结果评价原理及方法函数主要参数说明Python代码实现 示例反思与总结 写在前面的话
  • 《Python爬虫技术:深入理解原理、技术与开发》读书笔记(一)

    目录 前言第1章 基础知识第2章 爬虫基础HTTP基础URL与URI超文本HTTP与HTTPSHTTP的请求过程Network面版 前言 这是本系列的第一篇文章 xff0c 文如其题 xff0c 这个系列旨在学习Python爬虫技术 本系列
  • 给软件工程师的自学建议

    给软件工程师的自学建议 与现在大学生的情况类似 xff0c 学校学的专业知识总是与实际工作中需要的知识相差甚远 或许进入我们这个行业就注定要一辈子不离书本 不离学习了 由于软硬件技术的推陈出新 xff0c 学校教的C Basic Pasca
  • Python基础入门—for循环

    Python基础入门 for循环 for 循环 xff1a range的使用 xff1a 循环控制语句 xff1a for else的使用 xff1a for循环嵌套 xff1a for 循环 xff1a for循环格式 xff1a for
  • 软件测试之项目总结全攻略

    在我们测试工作过程中 xff0c 由于公司业务发展 xff0c 快速迭代等原因 xff0c 我们遇到的项目以小项目居多 更新界面元素 xff0c 上个活动页 xff0c 优化一下原有的功能等等 xff0c 加上事情繁琐 xff0c 任务多
  • 教你用Python写一个京东自动下单抢购脚本(Python实现京东自动抢购)

    很多朋友都有网购抢购限量商品的经历 有时候蹲点抢怎么也抢不到 今天小编带你们学习怎么用Python写一个京东自动下单抢购脚本 以后再也不用拼手速拼网速啦 快来一起看看吧 1 问题背景 经过无数次抢购失败后 xff0c 发现商家会不定时的放出
  • JAVA基础题练习

    顺序插入 xff1a 插入有序 Scanner input 61 new Scanner System in char arr2 61 39 b 39 39 d 39 39 f 39 39 i 39 39 k 39 39 m 39 39 x
  • ubuntu20.04安装qq音乐并解决闪退问题

    在qq音乐官网下载linux版coco音乐 xff1a https y qq com download download html 下载deb包并且通过下面命令行安装 xff1a span class token function sudo
  • 架构师装逼核武器

    架构师这个职位是很多程序猿的梦想 xff0c 我有很多朋友私下和我聊天的时候 xff0c 曾多次问我要如何才能成为一个架构师 xff0c 对于这个问题 xff0c 我只能粗略的谈谈我个人的观点 xff0c 如有不同观点 xff0c 欢迎交流
  • 一文讲透java日志框架

    在项目开发过程中 xff0c 有一个必不可少的环节就是记录日志 xff0c 相信只要是个程序员都用过 xff0c 可是咱们自问下 xff0c 用了这么多年的日志框架 xff0c 你确定自己真弄懂了日志框架的来龙去脉嘛 xff1f 下面笔者就
  • HashMap底层原理

    在我们实际的项目中 xff0c HashMap这个集合类经常被用到 xff0c 可是就是这么一个常用的集合类 xff0c 却往往成了咱们面试中的绊脚石 即便你是个初级程序员 xff0c 也常会让你谈谈HashMap的底层原理 xff0c 今
  • 聊聊ThreadPoolExecutor线程池

    ThreadPoolExecutor是线程的池化技术 xff0c 也就是首先创建几个线程 xff0c 然后把线程放到池子里 xff0c 有任务来的时候直接从线程池中拉线程来执行任务 为什么要用池化技术 xff1f java中的线程是系统级别
  • Spring框架系列之bean的生命周期底层原理06

    bean的生命周期 xff0c 咱们必须从 AnnotationConfigApplicationContext的getBean方法开始 xff0c getBean顾名思义就是从Spring容器中得到一个Bean的实例对象 xff0c Sp
  • 电信运营商移动互联网发展分析

    电信运营商移动互联网发展分析 移动互联网是通信业发展的大趋势 xff0c 随着3G 和WiMAX 等高速无线接入技术的飞速发展 xff0c 移动互联网不仅继承固定互联网的很多技术 xff0c 并且在商务 娱乐以及移动性等方面拓展用户需求 自
  • Spring框架系列之bean的生命周期底层原理07

    上一篇我们预留了两个大的内容 xff0c 一个是Object sharedInstance 61 getSingleton beanName 从单例池中获取数据 xff0c 另外一个是getSingleton方法创建单例Bean xff0c