Spring-基于xml自动装配

news2024/12/24 8:58:37

版本 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.coloradmin.cn/o/1613135.html

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

相关文章

打破国外垄断|暴雨发布纯血国产电脑

要说现在国产手机这边已然进入纯自研模式&#xff0c;但电脑这边却还是仍未打破国外技术垄断。但就在刚刚&#xff0c;暴雨发布自研架构台式机open Station X &#xff0c;这是纯血鸿蒙系统之后国产又一款纯血产品发布&#xff01;标志的我们已经彻底打破西方在硬件及软件方面的…

编译一个基于debian/ubuntu,centos,arhlinux第三方系统的问题解答

如果是开机卡boot注意看前面几行会有错误提示&#xff0c;一般会比较好找&#xff0c;下面是过了kernel内核加载后出现的问题 目录 上一篇文章 第一个问题 错误原因 解决办法 第二个问题 注意 第三个问题 上一篇文章 编译一个基于debian/ubuntu,centos,arhlinux第三方系…

垃圾收集器ParNewCMS与底层三色标记算法详解

垃圾收集算法 分代收集理论 当前虚拟机的垃圾收集都是采用分代收集算法,这种算法没有什么新思想,只是依据对象的存活周期不同将内存分为几块.一般将Java堆分为新生代和老年代,这样就可以根据各个年代的特点选择合适的垃圾收集算法. 比如在新生代中,每次收集都会有大量对象(近…

【Linux开发 第九篇】磁盘分区

Linux磁盘分区 磁盘分区 Linux分区是用来组成整个文件系统的一部分 Linux采用了一种叫载入的处理方法&#xff0c;它的整个文件系统中包括了一整套的文件和目录&#xff0c;且将一个分区和一个目录联系起来&#xff0c;这时要载入的一个分区将使它的存储空间开一个目录下获得…

基于spark进行数据分析的心力衰竭可视化大屏项目

基于spark进行数据分析的心力衰竭可视化大屏项目 项目背景 在当今的医疗领域&#xff0c;数据驱动的决策变得日益重要。心力衰竭作为常见的心血管疾病&#xff0c;其临床数据的分析对于改善患者治疗结果至关重要。本文将介绍如何利用Apache Spark进行大规模心力衰竭临床数据的…

单例模式与反射创建对象

单例模式 饿汉式单例模式 单例模式&#xff0c;就是自己先把自己创建了&#xff0c;整个程序都只有这一个实例&#xff0c;别人都没有办法创建实例&#xff0c;因为他的构造方法是private的 一次性把全部都创建了 public class HungryMan {private static int [][] s new …

linux的编译器vim

vim简介 之前我们在win下写代码&#xff0c;都是下载一些编译器VS/eclipse等 他们不仅可以写代码&#xff0c;还可以实现代码的运行调试&#xff0c;开发。这样的编译器叫做集成编译器 而linux中虽然也有这样的编译器&#xff0c;但不管是从下载&#xff0c;还是使用中都会显…

利用Opencv4.9为图像添加边框

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇利用OpenCV4.9制作自己的线性滤波器&#xff01; 下一篇 :OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 目标 在本教程中&#xff0c;您将学习如何&#xff1a; 使用 OpenCV 函数 …

Java基于微信小程序的讲座预约系统的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

拿捏 顺序表(1)

目录 1. 顺序表的分类2. 顺序表实现3. 顺序表实现完整代码4. 总结 前言: 一天xxx想存储一组数据, 并且能够轻松的实现删除和增加, 此时数组大胆站出, 但是每次都需要遍历一遍数组, 来确定已经存储的元素个数, 太麻烦了, 于是迎来了顺序表不屑的调侃: 数组你不行啊… 顺序表是一…

学习亚马逊云科技AWS云计算技术的三款官方免费3A游戏大作

玩3A大作免费电脑游戏&#xff0c;就能成为AWS云架构师、云开发大&#x1f42e;&#xff1f;这么好的事尊的假的&#xff1f;小李哥今天就来给大家介绍&#xff0c;如何通过玩AWS官方的定制版虚拟人生、炉石传说和密室逃脱游戏学习AWS。这三个游戏完全免费&#xff0c;没有任何…

react之组件与JSX

第一章 - 描述用户界面 概述&#xff1a;React是一个用于构建用户界面&#xff08;UI&#xff09;的JavaScript库&#xff0c;用户界面由按钮&#xff0c;文本和图像等小单元内容构建而成。React帮助你把它们组合成可重用&#xff0c;可嵌套的组件。从web端网站到移动端应用&a…

利用Django中的缓存系统提升Web应用性能

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在构建现代Web应用时&#xff0c;性能通常是至关重要的考虑因素之一。为了提高用户体验和应…

云原生Kubernetes: K8S 1.29版本 部署ingress-nginx

目录 一、实验 1.环境 2. K8S 1.29版本 部署ingress-nginx 二、问题 1.kubectl 如何强制删除 Pod、Namespace 资源 2.创建pod失败 3.pod报错ImagePullBackOff 4.docker如何将镜像上传到官方仓库 5.创建ingress报错 一、实验 1.环境 &#xff08;1&#xff09;主机 表…

linux 下的 sqlite数据库

SQLite 认识 SQLite简介 轻量化&#xff0c;易用的嵌入式数据库&#xff0c;用于设备端的数据管理&#xff0c;可以理解成单点的数据库。传统服务器型数据库用于管理多端设备&#xff0c;更加复杂 SQLite是一个无服务器的数据库&#xff0c;是自包含的。这也称为嵌入式数据库&…

【免费源码下载】完美运营版商城 虚拟商品全功能商城 全能商城小程序 智慧商城系统 全品类百货商城php+uniapp

简介 完美运营版商城/拼团/团购/秒杀/积分/砍价/实物商品/虚拟商品等全功能商城 干干净净 没有一丝多余收据 还没过手其他站 还没乱七八走的广告和后门 后台可以自由拖曳修改前端UI页面 还支持虚拟商品自动发货等功能 挺不错的一套源码 前端UNIAPP 后端PHP 一键部署版本&am…

随机游走的艺术-图嵌入表示学习

图嵌入引入 机器学习算法&#xff1a; 厨师 样本集&#xff1a; 食材 只有好的食材才能做出好的饭菜 我们需要把数据变成计算机能够读懂的形式&#xff08;将数据映射成为向量&#xff09; 图嵌入概述 传统图机器学习 图表示学习 自动学习特征&#xff0c;将…

【Linux驱动层】iTOP-RK3568学习之路(三):字符设备驱动框架

一、总体框架图 二、字符设备相关函数 静态申请设备号 register_chrdev_region 函数原型&#xff1a;register_chrdev_region(dev_t from, unsigned count, const char *name) 函数作用&#xff1a;静态申请设备号&#xff0c;可以一次性申请多个连续的号&#xff0c;count指定…

从头开始构建自己的 GPT 大型语言模型

图片来源&#xff1a; Tatev Aslanyan 一、说明 我们将使用 PyTorch 从头开始构建生成式 AI、大型语言模型——包括嵌入、位置编码、多头自注意、残差连接、层归一化&#xff0c;Baby GPT 是一个探索性项目&#xff0c;旨在逐步构建类似 GPT 的语言模型。在这个项目中&#xff…

【教程】MySQL数据库学习笔记(五)——约束(持续更新)

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【MySQL数据库学习】系列文章 第一章 《认识与环境搭建》 第二章 《数据类型》 第三章 《数据定义语言DDL》 第四章 《数据操…