Spring IOC - BeanDefinition解析

1. BeanDefinition的属性        

        BeanDefinition作为接口定义了属性的get、set方法。这些属性基本定义在其直接实现类AbstractBeanDefinition中,各属性的含义如下表所示:

类型

名称

含义

常量

SCOPE_DEFAULT

默认作用域:单例模式

AUTOWIRE_NO

没有自动装配

AUTOWIRE_BY_NAME

按名称自动装配

AUTOWIRE_BY_TYPE

按类型自动装配

AUTOWIRE_CONSTRUCTOR

按最匹配的构造方法自动装配

AUTOWIRE_AUTODETECT

对bean类进行内省来确定合适的自动装配策略

DEPENDENCY_CHECK_NONE

不进行依赖关系依赖关系检查

DEPENDENCY_CHECK_OBJECTS

对对象引用进行依赖关系检查

DEPENDENCY_CHECK_SIMPLE

对简单属性进行依赖关系检查

DEPENDENCY_CHECK_ALL

对所有属性进行依赖关系检查

INFER_METHOD

容器应尝试推断销毁方法名称,而不是显示指定方法名称

属性变量

beanClass

Bean 的Class对象

scope

作用域,默认为单例

abstractFlag

是否是抽象类标记,默认值为false,若为true,则不会实例化该bean

lazyInit

是否懒加载

autowireMode

自动装配模式,默认无

dependencyCheck

依赖关系检查,默认无

dependsOn

Bean依赖的其他Bean的名称

autowireCandidate

这个bean是否是自动装配到其他bean的候选项,默认为true

priary

这个bean是否是首要的自动装配候选项,默认为false

qulifiers

自动装配候选项限定符map,key:class对象名称(全类名)

instanceSupplier

为创建bean实例指定一个回调函数,作为声明性工厂方法的替代方案

nonPublicAccessAllowed

是否允许访问非公共的构造函数和方法,默认为true,标识允许

lenientConstructorResolution

是否以宽松模式或严格模式解析构造函数,默认为true,为宽松模式

factoryBeanName

工厂bean名称

factoryMethodName

工厂方法名称

constructorArgumentValues

构造函数参数值

propertyValues

属性值

methodOverrides

当前bean被重写的方法

initMethodName

初始化的方法的名称

destroyMethodName

销毁的方法的名称

enforceInitMethod

指定配置的方法是否为初始化方法,默认为true

enforceDestroyMethod

指定配置的方法是否为销毁方法,默认为true

synthetic

beanDefiniton是否是合成的,默认为false

role

角色提示,指BeanDefinition是应用程序的主要部分。通常是由用户定义的bean

description

beanDefiniton可读性高的描述

resource

beanDefinition来自的资源

2. 三个子类及属性        

        AbstractBeanDefinition有三个重要的直接子类,他们除了拥有父类的这些属性外,自己也有专门的属性,首先其类图如下所示:

        三个直接子类各自的属性如下表所示:

子类

属性名称

属性含义

GenericBeanDefinition

parentName

父bean名称

ChildBeanDefinition

parentName

父bean名称

RootBeanDefinition

decoratedDefinition

记录了beanName,别名等

qualifiedElement

记录了注解元素

stale

beanDefinition是否需要被重新合并

allowCaching

是否允许缓存,默认为true

isFactoryMethodUnique

工厂方法是否唯一,默认为false

resolvedTargetType

缓存class,表明RootBeanDefinition存储哪个类的信息

isFactoryBean

表名该Bean是否是工厂bean

factoryMethodReturnType

缓存工厂方法的返回类型

resolvedDestroyMethodName

缓存已解析的销毁方法名称

resolvedConstructorOrFactoryMethod

缓存已解析的构造函数或工厂方法

constructorArgumentsResolved

表明构造函数参数是否解析完毕,默认为false

resolvedConstructorArguments

缓存完成解析的构造函数参数

preparedConstructorArguments

缓存待解析的构造函数参数

postProcessed

表名是否被MergedBeanDefinitionPostProcessor处理过,默认为false

beforeInstantiationResolved

在生成代理时使用,表名是否已经生成代理

externallyManagedConfigMembers

记录了Contructor、Field、method类型的成员

externallyManagedInitMethods

InitializingBean中的init回调函数名,以便进行生命周期回调

externallyManagedDestroyMethods

DisposableBean的destroy回调函数名,以便进行生命周期回调

3. 三个子类的应用及区别

        在XML文件中定义一个bean时,Spring会创建一个RootBeanDefinition实例,这个实例会保存所有的配置信息,如类名、属性值等;

        当一个bean继承了另一个bean时,Spring会为子bean创建一个ChildBeanDefinition,为父bean创建一个RootBeanDefinition

        在配置类中使用@Bean注解定义bean时,Spring会创建一个GenericBeanDefinition实例;

        在类上使用注解(如@Component、@Service、@Repository等)来定义一个bean时,Spring会创建一个实现了AnnotatedBeanDefinition接口的实例:AnnotatedGenericBeanDefinitionScannedGenericBeanDefinition。这个实例会保存类名、类的类型、以及类上的所有注解信息;

    GenericBeanDefinitionAnnotatedBeanDefinition的主要区别如下:

        AnnotatedBeanDefinition保存了类上的注解信息,而GenericBeanDefinition没有。这就使得Spring能够在运行时读取和处理这些注解,提供更丰富的功能。

4. BeanDefinition的合并

        Spring中提供了多样的BeanDefinition,其最后都会被转换或合并为RootBeanDefinition,就是把子 BeanDefinition 的配置信息和父 BeanDefinition 的配置信息合并起来,形成一个完整的配置信息。合并后的 BeanDefinition 对象包含了 Bean 创建所需要的所有信息,Spring 将使用这个完整的 BeanDefinition 来创建 Bean 实例。

5. BeanDefinition的合并解析

        代码位于:AbstractBeanFactory#getMergedBeanDefinition

protected RootBeanDefinition getMergedBeanDefinition(
      String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
      throws BeanDefinitionStoreException {

   synchronized (this.mergedBeanDefinitions) {
      RootBeanDefinition mbd = null;
      RootBeanDefinition previous = null;

      // Check with full lock now in order to enforce the same merged instance.
      if (containingBd == null) {
         mbd = this.mergedBeanDefinitions.get(beanName);
      }

      if (mbd == null || mbd.stale) {
         previous = mbd;
         // 父bean为空
         if (bd.getParentName() == null) {
            // Use copy of given root bean definition.
            if (bd instanceof RootBeanDefinition) {
               // 原始的BeanDefinition为RootBeanDefinition,直接克隆
               mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
            }
            else {
               // 原始的BeanDefinition不是RootBeanDefinition,则new一个
               mbd = new RootBeanDefinition(bd);
            }
         }
         else {
            // 父bean不为空,需要合并
            // Child bean definition: needs to be merged with parent.
            BeanDefinition pbd;
            try {
               String parentBeanName = transformedBeanName(bd.getParentName());
               if (!beanName.equals(parentBeanName)) {
                  // 获取map中parentBeanName对应的RootBeanDefinition
                  pbd = getMergedBeanDefinition(parentBeanName);
               }
               else {
                  BeanFactory parent = getParentBeanFactory();
                  if (parent instanceof ConfigurableBeanFactory) {
                     pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                  }
                  else {
                     throw new NoSuchBeanDefinitionException(parentBeanName,
                           "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                           "': cannot be resolved without a ConfigurableBeanFactory parent");
                  }
               }
            }
            catch (NoSuchBeanDefinitionException ex) {
               throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                     "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
            }
            // Deep copy with overridden values.
            // 深拷贝
            mbd = new RootBeanDefinition(pbd);
            // 子bean初始化BeanDefinition的相关信息覆盖掉继承自RootBeanDefinition的相同信息
            mbd.overrideFrom(bd);
         }

         // Set default singleton scope, if not configured before.
         if (!StringUtils.hasLength(mbd.getScope())) {
            mbd.setScope(SCOPE_SINGLETON);
         }

         // A bean contained in a non-singleton bean cannot be a singleton itself.
         // Let's correct this on the fly here, since this might be the result of
         // parent-child merging for the outer bean, in which case the original inner bean
         // definition will not have inherited the merged outer bean's singleton status.
         if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
            mbd.setScope(containingBd.getScope());
         }

         // Cache the merged bean definition for the time being
         // (it might still get re-merged later on in order to pick up metadata changes)
         if (containingBd == null && isCacheBeanMetadata()) {
            this.mergedBeanDefinitions.put(beanName, mbd);
         }
      }
      if (previous != null) {
         copyRelevantMergedBeanDefinitionCaches(previous, mbd);
      }
      return mbd;
   }
}

        逻辑流程图如下所示:

        总结如下:

        若bean没有父亲,将当前beanDefinition通过克隆或深拷贝方式生成一个新的RootBeanDefinition,并返回;

        若bean有父亲,将父beanDefinition通过克隆或深拷贝方式生成一个新的RootBeanDefinition,再将子beanDefiniton属性覆盖RootBeanDefiniton的相同信息,并返回该RootBeanDefinition.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《Semantics Disentangling for Generalized Zero-Shot Learning》论文解读

其实除了VAE自监督外,引入语义属性来约束生成特征的质量。感觉解纠缠这个说法有点扯淡。 语义相关模块的作用 其实就是把语义属性也作为标签。除了VAE外,加了语义属性作为标签,这样生成的特征就可以即跟原始视觉特征对齐,又跟语…

大数据治理运营整体解决方案:PPT全文39页,附下载

关键词:大数据,数据治理,数据治理解决方案,数据治理的目的和意义 一、数据治理的定义 数据治理专注于将数据作为企事业单位数据资产进行应用和管理的一套管理机制,能够消除数据的不一致性,建立规范的数据应…

5年测试经验之谈:2年功能测试、3年自动化测试,从入门到25k...

毕业3年了,学的是环境工程专业,毕业后零基础转行做软件测试。 已近从事测试行业8年了,自己也从事过2年的手工测试,从事期间越来越觉得如果一直在手工测试的道路上前进,并不会有很大的发展,所以通过自己的努…

Ansible角色定制实例

目录 角色定制:roles 角色定制实例:利用角色部署wordpress 1.在roles目录下生成对应的目录结构 2.定义配置文件 ①nginx ②php ③mysql ④定义剧本文件 ⑤启动服务 角色定制:roles 对于普通的剧本(playbook)有…

web前端开发第3次Dreamweave课堂练习/html练习代码《网页设计语言基础练习案例》

目标图片: 文字素材: 网页设计语言基础练习案例 ——几个从语义上和文字相关的标签 * h标签(h1~h6):用来定义网页的标题,成对出现。 * p标签:用来设置网页的段落,成对出现。 * b…

Linux下的文件系统

文章目录 一、初始文件系统 二、理解磁盘文件 三、了解磁盘 四、深入理解磁盘文件 4、1 磁盘分区 4、2 分区存储细节 4、3 磁盘文件的操作 4、3、1 查找某个磁盘文件 4、3、2 创建文件 4、3、3 对文件进行写入 4、3、4 删除文件 4、4 再次理解文件权限 🙋‍♂️ 作…

Spring 重点知识总结(三)——AOP

前言 基于黑马《SSM框架教程》的学习笔记,附链接:SSM框架教程 1 AOP 核心概念 AOP :(Aspect Oriented Programming)面向切面编程,是一种编程范式,负责指导开发者组织程序结构 同 OOP (Object …

AI图像生成模型LCMs: 四个步骤就能快速生成高质量图像的新方法

在最新的AI模型和研究领域,一种名为Latent Consistency Models(LCMs)的新技术正迅速推动文本到图像人工智能的发展。与传统的Latent Diffusion Models(LDMs)相比,LCMs在生成详细且富有创意的图像方面同样出色,但仅需1-…

python打包部署脚本

linux可使用expect来实现自动交互,windows想要写出同样的功能脚本,只能使用python或者安装ActiveTcl 1、安装python Microsoft Store搜索python直接安装,默认会直接添加到环境变量https://www.python.org/官网下载,点击安装时会提…

初识MySQL(一)(创建数据库,查看删除数据库,备份和恢复,创建表,数据类型)

目录 客户端 ------> MySQL服务(3306) 数据库三层结构-破除MySQL神秘 创建数据库 查看删除数据库 备份恢复数据库 创建表 MySQL常用的数据类型(列类型) ​编辑 ​编辑整型 bit类型 小数类型 字符串类型 日期类型的使用 客户端 ------> MySQL服务(3306) 连接…

【斗破年番】毒宗决战万蝎门,小医仙惨遭背叛,斗宗巅峰蝎毕岩

Hello,小伙伴们,我是小郑继续为大家深度解析国漫资讯。 深度爆料斗破年番第七十话剧情解析,万蝎门宗主蝎毕岩,也算是这片大陆上的一小小块势力。一年前,他曾与小医仙正面交锋,即使当时的蝎毕岩已经站在了四星斗宗&…

2023年【广东省安全员B证第四批(项目负责人)】考试及广东省安全员B证第四批(项目负责人)试题及解析

题库来源:安全生产模拟考试一点通公众号小程序 广东省安全员B证第四批(项目负责人)考试考前必练!安全生产模拟考试一点通每个月更新广东省安全员B证第四批(项目负责人)试题及解析题目及答案!多…

若依系统富文本框上传图片报错!

报错如下: 原因:如图,富文本路径中存在 / 字符,导致上传出错。 解决方案:将富文本框内容在前端进行加密,后端再解密。 前端: 安装 crypto-js 插件 npm install crypto-js 创建工具类 :在 sr…

阿里云国际站:应用实时监控服务

文章目录 一、阿里云应用实时监控服务的概念 二、阿里云应用实时监控服务的优势 三、阿里云应用实时监控服务的功能 四、写在最后 一、阿里云应用实时监控服务的概念 应用实时监控服务 (Application Real-Time Monitoring Service) 作为一款云原生可观测产品平台&#xff…

微服务拆分的一些基本原则

文章首发公众号:海天二路搬砖工 单一职责原则 什么是单一职责原则 单一职责原则原本是面向对象设计中的一个基本原则,它指的是一个类只负责一项职责,不要存在多于一个导致类变更的原因。 在微服务架构中,一个微服务也应该只负…

使用vitis调试时debug按钮灰化无法进行操作

问题 使用vitis调试时debug按钮灰化无法进行操作。 原因 bitstream文件配置有误。 解决办法 重新配置正确的bitstream文件,如下:

Vue基础之组件通信(二)

个人名片: 😊作者简介:一名大二在校生 🤡 个人主页:坠入暮云间x 🐼座右铭:懒惰受到的惩罚不仅仅是自己的失败,还有别人的成功。 🎅**学习目标: 坚持每一次的学习打卡 文章…

通过实例fpmarkets讲解三智者交易策略

今天fpmarkets和大家一起用实例解释三智者交易策略。 在每日BTCUSD图中,椭圆形区域标志着多头反转棒线。它创下了当地新低,但收盘时接近最高点。它标志着下半年的市场情绪更加乐观。酒吧在鳄鱼嘴的外面。 多头进场放在多头发散棒顶部上方。在这里fpmarke…

深度神经网络算子参数量和计算量分析—卷积篇

前言 在用于计算机视觉任务的深度神经网络模型中,卷积算子作为一种重要的特征提取方式被广泛应用,本文针对常见的卷积算子参数量和计算量的计算方法进行分析,主要包括普通卷积、深度可分离卷积、分组卷积,以及自动计算模型参数量和…

【Cookie 和 session 的区别】

会话(Session) 跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。cookie和session都是用来跟踪浏览器用户身份的会话方式。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。 我们目前使用…