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

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);}}

 

总结

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 离线下载linux mysql和mysql基本库
  • JS实现:统计字符出现频率/计算文字在文本中的出现次数
  • 【大规模训练】混合专家系统
  • 【算法】平衡二叉树
  • 【CUDA|CUDNN】安装
  • CANoe:为什么两个VLAN接口不能设置同一个网络的IP地址呢?
  • Django 常见的操作符
  • 修复 Ubuntu 24.04 Dock 丢失应用程序图标
  • 数据结构--二叉树相关习题5(判断二叉树是否是完全二叉树 )
  • uniapp如何发送websocket请求
  • Python函数 之 变量
  • 前端导出pdf
  • Science Advances 仿生双模态触觉感知
  • c++ 多边形 xyz 数据 获取 中心点方法,线的中心点取中心值搞定 已解决
  • PMON的解读和开发
  • October CMS - 快速入门 9 Images And Galleries
  • oldjun 检测网站的经验
  • pdf文件如何在线转换为jpg图片
  • python学习笔记-类对象的信息
  • React的组件模式
  • SpiderData 2019年2月13日 DApp数据排行榜
  • SQLServer之索引简介
  • 构建工具 - 收藏集 - 掘金
  • 讲清楚之javascript作用域
  • 码农张的Bug人生 - 见面之礼
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 区块链分支循环
  • 使用 @font-face
  • 用element的upload组件实现多图片上传和压缩
  • 在Docker Swarm上部署Apache Storm:第1部分
  • 阿里云ACE认证之理解CDN技术
  • ​520就是要宠粉,你的心头书我买单
  • ​第20课 在Android Native开发中加入新的C++类
  • #Datawhale AI夏令营第4期#AIGC文生图方向复盘
  • #pragma multi_compile #pragma shader_feature
  • $nextTick的使用场景介绍
  • (13):Silverlight 2 数据与通信之WebRequest
  • (21)起落架/可伸缩相机支架
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (33)STM32——485实验笔记
  • (Charles)如何抓取手机http的报文
  • (C语言)球球大作战
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (MTK)java文件添加简单接口并配置相应的SELinux avc 权限笔记2
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (六)c52学习之旅-独立按键
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (十六)Flask之蓝图
  • (小白学Java)Java简介和基本配置
  • .bat文件调用java类的main方法
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .NET程序集编辑器/调试器 dnSpy 使用介绍
  • .net和php怎么连接,php和apache之间如何连接
  • .net开发时的诡异问题,button的onclick事件无效