Spring-基于xml自动装配

版本 Spring Framework 6.0.9​

1. 定义

Spring IoC容器在无需显式定义每个依赖关系的情况下,根据指定的策略,自动为指定的bean中所依赖的类类型或接口类型属性赋值。

2. 关键配置元素

BeanDefinitionParserDelegate类定义了autowire属性的属性值,代表了不同的自动装配策略。
在这里插入图片描述

2.1 < bean>元素的autowire属性

在XML配置文件中定义时,可以为其设置autowire属性来启用自动装配。该属性可取以下值:

  • byType
    Spring容器会查找容器中与目标bean属性类型相匹配的所有bean,并将其中的一个(如果有多个同类型bean,则选择其中一个,具体选择规则取决于容器的处理逻辑)注入到该属性。
  • byName
    Spring容器尝试按属性名作为bean的ID在容器中查找相应的bean。即如果目标bean有一个名为car的属性,那么容器会查找ID为car的bean并将其注入。
  • constructor
    Spring容器会查找与bean构造器参数类型相匹配的bean,并通过构造器注入的方式创建bean实例。
  • defaultno
    禁用自动装配,default 会转换成 nono 是Spring的默认设置。所有依赖项必须通过显式配置(如或标签)来注入。

2.2 < beans>标签的default-autowire属性

在< beans>元素上可以设置default-autowire属性,用于指定整个配置文件中所有未显式指定autowire属性的的默认自动装配策略。该属性可选值与 < bean>元素的autowire属性一样(byType、byName、constructor、default、no)。

3. 原理

3.1 获取autowire的默认值

在基于xml配置的ioc容器中,spring会创建一个DocumentDefaultsDefinition对象,并通过BeanDefinitionParserDelegate#populateDefaults方法进行初始化,使用默认的 lazy-init、autowire、依赖项检查设置、init-method、destroy-method 和 merge 填充,以防未在本地显式设置默认值。

红圈部分的代码在处理Spring XML配置文件中 标签的默认自动装配属性。

  1. 从当前 < beans> 标签节点中获取名为DEFAULT_AUTOWIRE_ATTRIBUTE(default-autowire)的属性值,
  2. 如果获取到的autowire值为空或等于default,则从父级获取自动装配模式(如果有);否则,使用预定义的常量AUTOWIRE_NO_VALUE(no)作为默认值,即不进行自动装配。
  3. 最后将计算得到的autowire值(即当前标签的默认自动装配模式)设置到defaults对象中,作为默认设置的对象,以便后续处理或传递给其他方法。

这样做的目的是确保每个< beans>标签都有一个明确的默认自动装配设置,以便在解析其内部bean定义时使用。
在这里插入图片描述

  • DEFAULT_AUTOWIRE_ATTRIBUTE
    在这里插入图片描述
  • AUTOWIRE_NO_VALUE
    在这里插入图片描述
  • isDefaultValue
    在这里插入图片描述

3.2 解析autowire的属性值

红圈部分的代码在处理Spring XML配置文件中 标签的自动装配属性。

  1. 从当前 < bean> 标签节点中获取名为AUTOWIRE_ATTRIBUTE(autowire)的属性值。
  2. 用刚刚获取的属性值作为入参attrValue调用autowire方法
    • 如果attrValue为空或者default,从defaults对象中获取默认的自动装配模式字符串,并将其赋值给attr。即上面提到的默认值(一般情况下为no)。
    • 初始化整型变量autowire,将其值设为AbstractBeanDefinition.AUTOWIRE_NO,表示默认不进行自动装配。
    • 根据attr值的不同,分别设置autowire变量为不同的自动装配模式整数值(byName=1,byType=2,constructor=3,autodetect=4)。另外,autodetect模式已被标记为@Deprecated,提示用户应尽量避免使用。
  3. 最后将计算得到的autowire整型值设置到对应的BeanDefinition对象中(autowireMode属性)。

在这里插入图片描述

3.3 使用autowire的属性值

根据autowire属性值执行自动装配:

  • byType:容器遍历bean的所有setter方法(或无参构造器后有setter的字段),查找与setter参数类型相匹配的bean。找到匹配项后,调用对应的setter方法进行注入。
  • byName:容器查找bean的所有setter方法(或无参构造器后有setter的字段),根据setter方法名(去掉set前缀,将首字母小写)或字段名作为bean ID在容器中查找bean。找到匹配项后,调用setter方法或直接赋值进行注入。
  • constructor:容器分析bean的构造器参数,查找与每个参数类型相匹配的bean。找到匹配项后,通过构造器注入方式创建bean实例。

3.3.1 byType

在bean声明周期的属性填充(populateBean方法)阶段,从bean定义中获取自动装配模式(autowireMode),如果值为autowireMode=2(AUTOWIRE_BY_TYPE=2),调用autowireByType方法执行按类型装配。
在这里插入图片描述

autowireByType的方法,用于按类型自动装配给定bean的属性。获取当前bean中所有待自动装配的非简单属性名称。遍历这些属性名称,通过resolveDependency方法获取满足依赖关系的bean实例,注入到对应属性。通过该方法,Spring IoC容器能够根据bean的类型自动为其属性注入合适的依赖bean实例。
在这里插入图片描述

unsatisfiedNonSimpleProperties(mbd, bw);

unsatisfiedNonSimpleProperties的方法为了找出给定AbstractBeanDefinition和BeanWrapper对象中未被显式设置且非简单的待自动装配属性名称。条件如下:
- 具有写方法
- 未被排除在依赖检查中
- PropertyValues中未已包含该属性的名称,即该属性尚未被显式设置。
- 非简单类型

在这里插入图片描述

bw.getPropertyDescriptor(propertyName)

BeanWrapper#getPropertyDescriptor方法获取属性的描述器,如下例子,定义一个UserController类,其包含一个userService属性,在xml配置文件中配置根据类型自动装配。getPropertyDescriptor方法返回两个类型为GenericTypeAwarePropertyDescriptor的描述器。
- propertyType为class,包含读方法getClass(),没有写方法
- propertyType为userService,没有读方法,包含写方法public void org.springframework.learn.ioc.auto.UserController.setUserService(org.springframework.learn.ioc.auto.UserService)

在这里插入图片描述
在这里插入图片描述

BeanUtils.getWriteMethodParameter(pd);

根据传入的PropertyDescriptor对象类型,分别从GenericTypeAwarePropertyDescriptor子类实例或普通PropertyDescriptor实例中提取与属性关联的写方法,并封装为MethodParameter对象返回。从上面getPropertyDescriptor方法中可知,返回的是GenericTypeAwarePropertyDescriptor子类实例,提取与属性关联的写方法。即是上面案例中的setUserService方法.。在这里插入图片描述

resolveDependency(desc, beanName, autowiredBeanNames, converter);

resolveDependency方法可以分成三种解析情况

  • 特殊类型的依赖解析:Optional类型、ObjectFactory/ObjectProvider类、javax.inject.Provider类。
  • 支持延迟解析:尝试获取一个用于延迟解析依赖的代理对象
  • 常规依赖解析:调用doResolveDependency方法解析依赖(一般情况下解析出符合所需类型的名称后,调用bean工厂的getBean方法获取bean实例)

resolveDependency方法根据依赖类型的差异采用不同的解析策略,包括创建适配特定类型的依赖提供者、支持延迟解析以及进行常规依赖解析。最终,该方法返回解析后的依赖对象。
在这里插入图片描述
doResolveDependency方法作用是解析依赖项。一般情况下,逻辑可以简单划分两部分

  • 解析依赖值(descriptor包含依赖项),获取bean名称。
  • 通过bean工厂获取bean实例并返回。

具体逻辑该方法会处理多种场景以解析由DependencyDescriptor描述的依赖项,同时考虑bean名称、自动装配规则及类型转换。它根据依赖项是否成功解析返回解析后的依赖项对象或针对各种错误条件抛出异常。
在这里插入图片描述

registerDependentBean(autowiredBeanName, beanName);

registerDependentBean方法用于注册两个相互依赖的bean之间的关系(两个内部数据结构dependentBeanMap 和 dependenciesForBeanMap),比如上述案例

  • dependentBeanMap:key=依赖Bean(属性userService)
  • dependenciesForBeanMap:key=依赖Bean的依赖项(userController)

在这里插入图片描述
在这里插入图片描述

3.3.2 byName

在bean声明周期的属性填充(populateBean方法)阶段,从bean定义中获取自动装配模式(autowireMode),如果值为autowireMode=1(AUTOWIRE_BY_NAME=1),调用autowireByName方法执行按名称装配。
在这里插入图片描述
autowireByName方法则比较简单,相较于autowireByType少了类型匹配的捕捉,先判断bean工厂是否包含bean名称,若包含则按照bean名称自动装配bean的属性(getBean方法获取bean实例)。
在这里插入图片描述

3.3.3 constructor

在bean声明周期的实例化(createBeanInstance方法)阶段,从bean定义中获取自动装配模式(autowireMode),如果值为autowireMode=3(AUTOWIRE_CONSTRUCTOR=2),调用autowireConstructor方法查找与bean构造器参数类型相匹配的bean,并通过构造器注入的方式创建bean实例。

在这里插入图片描述

autowireConstructor方法创建了一个包含当前bean工厂的构造函数解析器ConstructorResolver,并调用其autowireConstructor方法,完成实际的构造函数自动装配工作…
在这里插入图片描述

ConstructorResolver#autowireConstructor方法根据给定的bean名称、bean定义、用户指定构造器(若有)和显式参数值(若有),选择合适的构造器及其参数,完成bean的实例化过程。简单的过程可以理解成确认最佳构造器和所需参数,然后完成bean实例化。
在这里插入图片描述

上面的方法是获取最佳构造器和所需参数,通过构造器实例化bean。没有自动装配的具体使用逻辑(只判断了是否自动装配)。实际上,构造器类型的自动装配体现在createArgumentArray方法中。

	argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);

步骤如下:

  1. 定义局部变量,如类型转换器converter、构造参数结果值args等。
  2. 遍历给定参数数组,从resolvedValues获取匹配的构造器参数,转换后(如果未转换)保存到结果args中。获取不到则进行自动匹配。
  3. 往bean工厂注册依赖bean关系。
  4. 返回解析后的参数结果args。
    在这里插入图片描述
例子

以下面配置为例子,看createArgumentArray方法

  • 定义一个名称为userController的UserController,有两个属性
    • name属性在配置文件的value值是一个spel表达式 #{userControllerNameUtil.getUserControllerName()},name属性的类型为String。
    • userService属性未配置,使用自动装配
  • 定义一个名称为userControllerNameUtil的UserControllerNameUtil类,用来提供name,其中getUserControllerName方法返回的是Interger类型。
  • 定义一个名称为userService的UserServiceImpl类。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

进入org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor方法,获取到bean定义的构造函数参数name的原始配置值 #{userControllerNameUtil.getUserControllerName()}
在这里插入图片描述

resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);方法解析spel表达式,调用UserControllerNameUtil类的getUserControllerName方法,获取到Integer类型的 123456 解析值。
在这里插入图片描述

调用createArgumentArray方法构造参数的结果值。
在这里插入图片描述

  • 处理构造参数userService
    在这里插入图片描述
    在这里插入图片描述
  • 处理构造参数name
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

参考

  • Spring使用有参构造器创建对象autowireConstructor方法

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

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

相关文章

绿联 安装transmission

绿联 安装transmission及中文UI 1、镜像 linuxserver/transmission:latest 2、安装 2.1、创建容器 按需配置权重。 2.2、基础设置 2.3、网络 桥接即可。 注&#xff1a;如果使用IPV6&#xff0c;请选择"host"模式。 注&#xff1a;如果使用IPV6&#xff0c;请选…

Git禁止松散对象loose objects弹窗

打开仓库时&#xff0c;弹窗如图 This repository currently has approximately XXXX loose objects.解决办法&#xff1a;见How to skip “Loose Object” popup when running ‘git gui’ Git v1.7.9 或以上版本&#xff0c;执行git config --global gui.gcwarning false

【计算机毕业设计】面向学生成绩分析系统产品功能介绍——后附源码

&#x1f389;**欢迎来到琛哥的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 琛哥&#xff0c;一名来自世界500强的资深程序猿&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 琛哥在深度学习任务中展现出卓越的能力&a…

NIO之ByteBuffer

NIO中的ByteBuffer是缓冲区&#xff0c;其中有几个比较重要的属性capacity&#xff0c;position和limit。 capacity&#xff1a; 其中&#xff0c;capacity是缓冲区的容量大小&#xff0c;在分配内存空间后不会改变。 limit&#xff1a; limit是限制位置&#xff0c;在读写模…

前端crypto-js, 文件加密,判断相同文件、图片(MD5,SHA256)

文章目录 前情提要应用场景实战解析最后前情提要 大家好,今天我们来接触一个库crypto-js 没错,上面是有道翻译的截图,为了我们得到的信息更权威,这个库是用来加密的,但介绍是说,已经停止维护,但并不影响我们在前端项目中的使用,所以学学也没有坏处 应用场景 判断图片…

亿发:新修订器械GSP重大变化,医疗器械GSP软件助力适应科学监管

随着医疗器械行业的快速发展和监管要求的提升&#xff0c;国家药监局近期发布了新修订的医疗器械GSP&#xff08;Good Storage Practice&#xff09;规范&#xff0c;旨在加强医疗器械流通环节的质量管理和监督&#xff0c;确保医疗器械的安全、有效和可追溯。这一重大变化为医…

万益蓝Wonderlab益生菌:吃雪糕的自由,我终于找回来了!

虽然现在不是夏天&#xff0c;但是我必须要来说一下&#xff01;我不仅在夏天可以吃雪糕&#xff01;冬天吃也完全没有问题&#xff01; 夏天&#xff0c;对于很多人来说&#xff0c;是雪糕、冷饮和冰镇西瓜的代名词。但对于我&#xff0c;这简直就是个“禁区”。每次看着别人…

SpringBoot项目启动的时候直接退出了?

SpringBoot项目启动的时候直接退出了&#xff1f; 如下图&#xff1a; 在启动SpringBoot项目的时候仅仅用了1.209s&#xff0c;然后直接退出了&#xff0c;也没有出现启动的项目对应的服务器端口号&#xff1f;为什么会这样呢&#xff1f;因为既然有服务器端口号 那么肯定会有…

【php开发工程师系统性教学】——Laravel框架(验证码)的配置和使用的保姆式教程

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

MySQL的事务相关的语句的使用

MySQL的事务相关的语句的使用 事务是数据库管理系统执行过程中的一个程序单位&#xff0c;由一个或多个数据库操作组成。MySQL作为一款流行的关系型数据库管理系统&#xff0c;支持事务处理&#xff0c;允许用户定义一系列的操作&#xff0c;这些操作要么完全执行&#xff0c;…

数仓建模—数仓架构发展史

数仓建模—数仓架构发展史 时代的变迁,生死的轮回,历史长河滔滔,没有什么是永恒的,只有变化才是不变的,技术亦是如此,当你选择互联网的那一刻,你就相当于乘坐了一个滚滚向前的时代列车,开往未知的方向,不论什么样的技术架构只有放在当前的时代背景下,才是有意义的,…

MySQl-8.3.0版本安装下载教程(超详细保姆级教程)

第一步&#xff0c;去百度找到MySQl官网 第二步,找到DOWNLOAD&#xff08;下载&#xff09; 第三步 第四步 第五步 第六步.选择倒数第2个 第七步 第八步然后根据步骤安装就好了

MultiCD工具:创建一个多引导Linux USB驱动器

众所周知&#xff0c;拥有一个可安装多个可用操作系统的 CD 或 USB 驱动器在各种情况下都非常有用。无论是为了快速测试或调试某些内容&#xff0c;还是只是重新安装笔记本电脑或 PC 的操作系统&#xff0c;这都可以为你节省大量时间。 在本文中&#xff0c;将介绍如何使用名为…

最新win11配置cuda以及cudnn补丁教程

1、首先使用指令 nvidia-smi 查看电脑支持的**最高cuda**版本&#xff0c;例如&#xff1a;本机 12.2 2、进入CUDA下载cuda安装包 https://developer.nvidia.com/cuda-toolkit-archive 2、点击上方绿色的链接&#xff0c;按照图中序号选择的即可&#xff0c;最后点击下载。 …

VUE识别图片文字OCR(tesseract.js)

效果:1&#xff1a; 效果图2&#xff1a; 一、安装tesseract.js npm i tesseract.js 二、静态页面实现 <template><div><div style"marginTop:100px"><input change"handleChage" type"file" id"image-input"…

计算机网络—— book

文章目录 一、概述1.互联网的核心部分1&#xff0e;电路交换的主要特点2&#xff0e;分组交换的主要特点 2.计算机网络的性能1&#xff0e;速率2&#xff0e;带宽3&#xff0e;吞吐量4&#xff0e;时延5&#xff0e;利用率 3.计算机网络体系结构协议与划分层次具有五层协议的体…

深度学习之视觉特征提取器——VGG系列

VGG 提出论文&#xff1a;1409.1556.pdf (arxiv.org) 引入 距离VGG网络的提出已经约十年&#xff0c;很难想象在深度学习高速发展的今天&#xff0c;一个模型能够历经十年而不衰。虽然如今已经有VGG的大量替代品&#xff0c;但是笔者研究的一些领域仍然有大量工作选择使用VG…

【nodejs】express-generator项目--创建接口及数据库连接

文章目录 一、创建接口1、路由routes&#xff08;1&#xff09;新建路由文件&#xff08;2&#xff09;注册路由 2、控制器controller&#xff08;1&#xff09;新建controller文件&#xff08;2&#xff09;代码 3、services&#xff08;1&#xff09;新建services文件&#x…

Linux - Docker 安装 Nacos

拉取 Nacos 镜像 使用以下命令从 Docker Hub 拉取最新版本的 Nacos 镜像&#xff1a; docker pull nacos/nacos-server启动 Nacos 容器 使用以下命令启动 Nacos 容器&#xff1a; docker run -d \--name nacos \--privileged \--cgroupns host \--env JVM_XMX256m \--env M…

oracle 清空回收站

参考官方文档 select * from user_recyclebin; select * from dba_recyclebin; ---清除回收站中当前用户下的对象 purge recyclebin; ---清除回收站中所有的对象 purge dba_recyclebin; ---清除回收站中指定用户的表 PURGE TABLE owner.table_name; ---清除回收站中指…