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

【Spring】Spring之依赖注入源码解析

1 Spring注入方式

1.1 手动注入

xml中定义Bean,程序员手动给某个属性赋值。

  • set方式注入
<bean name="userService" class="com.firechou.service.UserService"><property name="orderService" ref="orderService"/>
</bean>
  • 构造方法注入
<bean name="userService" class="com.firechou.service.UserService"><constructor-arg index="0" ref="orderService"/>
</bean>

1.2 自动注入

1.2.1 XML的autowire自动注入

<bean id="userService" class="com.firechou.service.UserService" autowire="byType"/>

Spring会自动的给userService中所有的属性自动赋值(不需要这个属性上有@Autowired注解,但需要这个属性有对应的set方法);
XML的自动注入底层其实也就是set方法注入和构造方法注入;

Bean的自动注入模式autowire:

  • byType

获取到set方法中的唯一参数的参数类型,并且根据该类型去容器中获取bean,如果找到多个,会报错。

  • byName

找到所有set方法所对应的XXX部分的名字,根据XXX部分的名字去获取bean。

  • constructor

通过构造方法注入,可以不写set方法;
如果存在多个构造方法,则通过构造方法推断来选择某个构造方法;
Spring利用构造方法的参数信息从Spring容器中去找Bean,找到Bean之后作为参数传给构造方法,从而实例化得到一个bean对象,并完成属性赋值(属性赋值的代码得程序员来写);

  • default
  • no

关闭autowire

PropertyDescriptor:
创建Bean的过程中,填充属性时,Spring会去解析当前类,解析类中每个方法得到对应的PropertyDescriptor对象,PropertyDescriptor中有几个属性:

  1. name:这个name并不是方法的名字,而是拿方法名字进过处理后的名字
    1. 如果方法名字以“get”开头,比如“getXXX”,那么name=XXX
    2. 如果方法名字以“is”开头,比如“isXXX”,那么name=XXX
    3. 如果方法名字以“set”开头,比如“setXXX”,那么name=XXX
  2. readMethodRef:表示get方法的Method对象的引用
  3. readMethodName:表示get方法的名字
  4. writeMethodRef:表示set方法的Method对象的引用
  5. writeMethodName:表示set方法的名字
  6. propertyTypeRef:如果有get方法那么对应的就是返回值的类型,如果是set方法那么对应的就是set方法中唯一参数的类型

什么是set和get方法:

  • get方法定义

方法参数个数为0个,并且方法名字以"get"开头,或者方法名字以"is"开头并且方法的返回类型为boolean

  • set方法定义

方法参数个数为1个,并且方法名字以"set"开头并且方法返回类型为void

1.2.2 @Autowired注解的自动注入

@Autowired注解相当于XML中的autowire属性的注解方式的替代;
@Autowired注解提供了与XML中autowire相同的功能,但是拥有更细粒度的控制和更广泛的适用性
XML中的autowire控制的是整个bean的所有属性,而@Autowired注解是直接写在某个属性、某个set方法、某个构造方法上的;
如果一个类有多个构造方法,那么如果用XML的autowire=constructor,无法控制到底用哪个构造方法,可以用@Autowired注解来直接指定想用哪个构造方法;
@Autowired注解还可以控制,哪些属性想被自动注入,哪些属性不想,这也是细粒度的控制;
@Autowired无法区分byType和byName,@Autowired是先byType,如果找到多个则byName;

@Autowired注解可以写在:

  1. 属性上:先根据属性类型去找Bean,如果找到多个再根据属性名确定一个
  2. 构造方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
  3. set方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个

2 寻找注入点

在创建一个Bean的过程中,Spring会利用AutowiredAnnotationBeanPostProcessor的**postProcessMergedBeanDefinition()**找出注入点并缓存。

找注入点的流程为:

  1. 遍历当前类的所有的属性字段Field
  2. 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该字段是一个注入点
  3. 如果字段是static的,则不进行注入
  4. 获取@Autowired中的required属性的值
  5. 将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到currElements集合中。
  6. 遍历当前类的所有方法Method
  7. 判断当前Method是否是桥接方法,如果是找到原方法
  8. 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法是一个注入点
  9. 如果方法是static的,则不进行注入
  10. 获取@Autowired中的required属性的值
  11. 将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到currElements集合中
  12. 遍历完当前类的字段和方法后,将遍历父类的,直到没有父类
  13. 最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合对象,并缓存

3 注入点进行注入

Spring在AutowiredAnnotationBeanPostProcessor的**postProcessProperties()**方法中,会遍历所找到的注入点依次进行注入。

字段注入:

  1. 遍历所有的AutowiredFieldElement对象。
  2. 将对应的字段封装为DependencyDescriptor对象
  3. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前字段所匹配的Bean对象。
  4. DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了
  5. 利用反射将结果对象赋值给字段。

Set方法注入:

  1. 遍历所有的AutowiredMethodElement对象
  2. 遍历将对应的方法的参数,将每个参数封装成MethodParameter对象
  3. MethodParameter对象封装为DependencyDescriptor对象
  4. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前方法参数所匹配的Bean对象。
  5. DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了
  6. 利用反射将找到的所有结果对象传给当前方法,并执行。

相关文章:

【Spring】Spring之依赖注入源码解析

1 Spring注入方式 1.1 手动注入 xml中定义Bean&#xff0c;程序员手动给某个属性赋值。 set方式注入 <bean name"userService" class"com.firechou.service.UserService"><property name"orderService" ref"orderService"…...

【微软知识】微软相关技术知识分享

微软技术领域 一、微软操作系统&#xff1a; 微软的操作系统主要是 Windows 系列&#xff0c;包括 Windows 10、Windows Server 等。了解 Windows 操作系统的基本使用、配置和故障排除是非常重要的。微软操作系统&#xff08;Microsoft System&#xff09;是美国微软开发的Wi…...

12.python设计模式【观察者模式】

内容&#xff1a;定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变的时候&#xff0c;所有依赖于它的对象得到通知并被自动更新。观者者模式又称为“发布-订阅”模式。比如天气预报&#xff0c;气象局分发气象数据。 角色&#xff1a; 抽象主题&#xf…...

重生之我要学C++第五天

这篇文章主要内容是构造函数的初始化列表以及运算符重载在顺序表中的简单应用&#xff0c;运算符重载实现自定义类型的流插入流提取。希望对大家有所帮助&#xff0c;点赞收藏评论&#xff0c;支持一下吧&#xff01; 目录 构造函数进阶理解 1.内置类型成员在参数列表中的定义 …...

复习之linux高级存储管理

一、lvm----逻辑卷管理 1.lvm定义 LVM是 Logical Volume Manager&#xff08;逻辑卷管理&#xff09;的简写&#xff0c;它是Linux环境下对磁盘分区进行管理的一种机制。 逻辑卷管理器(LogicalVolumeManager)本质上是一个虚拟设备驱动&#xff0c;是在内核中块设备和物理设备…...

HuggingGPT Solving AI Tasks with ChatGPT and its Friends in Hugging Face

总述 HuggingGPT 让LLM发挥向路由器一样的作用&#xff0c;让LLM来选择调用那个专业的模型来执行任务。HuggingGPT搭建LLM和专业AI模型的桥梁。Language is a generic interface for LLMs to connect AI models 四个阶段 Task Planning&#xff1a; 将复杂的任务分解。但是这里…...

java工程重写jar包中class类覆盖问题

结论&#xff1a;直接在程序中复写jar中的类即可 原因&#xff1a;一般我java工程是运行在tomcat容器中&#xff0c;tomcat容易在加载我们工程类和jar包是的优先级为&#xff1a; 我们工程的class 先于 我们工程lib下的jar 重复的类只加载一次&#xff0c;加载我们复写后的类后…...

Mybatis基于注解与XML开发

文章目录 1 关于SpringBoot2 关于MyBatis2.1 MyBatis概述2.2 MyBatis核心思想2.3 MyBatis使用流程3 MyBatis配置SQL方式3.1 基于注解方式3.1.1 说明3.1.2 使用流程3.1.3 常用注解 3.2 基于XML方式3.2.1 相比注解优势3.2.2 使用流程3.2.3 常用标签 1 关于SpringBoot SpringBoot…...

数字化转型导师坚鹏:数字化时代扩大内需的8大具体建议

在日新月异的数字化时代、复杂多变的国际化环境下&#xff0c;扩大内需成为推动经济发展的国家战略&#xff0c;如何真正地扩大内需&#xff1f;结合本人15年的管理咨询经验及目前实际情况的深入研究&#xff0c;提出以下8大具体建议&#xff1a; 1、制定国民收入倍增计划。结…...

M1/M2 通过VM Fusion安装Win11 ARM,解决联网和文件传输

前言 最近新入了Macmini M2&#xff0c;但是以前的老电脑的虚拟机运行不起来了。&#x1f605;&#xff0c;实际上用过K8S的时候&#xff0c;会发现部分镜像也跑不起来&#xff0c;X86的架构和ARM实际上还是有很多隐形兼容问题。所以只能重新安装ARM Win11&#xff0c;幸好微软…...

Linux中显示系统正在运行的进程的命令

2023年7月29日&#xff0c;周六上午 在Linux中&#xff0c;ps命令用于显示当前系统中正在运行的进程&#xff0c; ps应该是processes snapshot&#xff08;进程快照&#xff09;的缩写。 以下是ps命令的常见用法和示例&#xff1a; 显示当前用户的所有进程&#xff1a;ps 显示…...

vite中安装less

使用vite创建的项目&#xff0c;默认是没有安装less的 如果直接在style中书写less 会报下图错误&#xff1a; 解决方案&#xff1a; npm install --save less 在package.json中查看是否安装成功 安装完成刷新页面&#xff0c;问题解决...

Aduino中eps环境搭建

这里只记录Arduino2.0以后版本&#xff1a;如果有外网环境&#xff0c;那么可以轻松搜到ESP32开发板环境并安装&#xff0c;如果没有&#xff0c;那就见下面操作&#xff1a; 进入首选项&#xff0c;将esp8266的国内镜像地址填入&#xff0c;然后保存&#xff0c;在开发板中查…...

python——案例二 求两个数的和

#案例二 求两个数的和 num1input(请输入第一个数字&#xff1a;) num2input(请输入第二个数字&#xff1a;) sumfloat(num1)float(num2) #计算公式 print(sum) #显示结果 输入num11、num22得到结果sum3...

一文了解 Android 车机如何处理中控的旋钮输入?

前言 上篇文章《从实体按键看 Android 车载的自定义事件机制》带大家了解了 Android 车机支持自定义输入的机制 CustomInputService。事实上&#xff0c;除了支持自定义事件&#xff0c;对于中控上常见的音量控制、焦点控制的旋钮事件&#xff0c;Android 车机也是支持的。 那…...

小红书推广 方法总结

大家好&#xff0c;我是网媒智星&#xff0c;今天跟大家分享一下小红书的推广方法和经验。 一、平台简介 1、什么是小红书&#xff1f; 小红书是一个消费决策/生活方式平台&#xff0c;用户可以通过图片、文案、视频等方式分享美好生活。 2、用户画像 - 2亿月活跃…...

通讯录的实现(超详细)——C语言(进阶)

目录 一、创建联系人信息&#xff08;结构体&#xff09; 二、创建通讯录&#xff08;结构体&#xff09; 三、define定义常量 四、打印通讯录菜单 五、枚举菜单选项 六、初始化通讯录 七、实现通讯的的功能 7.1 增加加联系人 7.2 显示所有联系人的信息 ​7.3 单独查…...

3D 渲染技巧-如何创建高质量写实渲染?

掌握创建高质量建筑渲染和任何 3D 渲染的艺术是一项复杂且需要技巧的工作&#xff0c;通常需要多年的经验和实践。实现逼真的结果需要仔细考虑众多因素&#xff0c;并避免可能导致缺乏真实性的假渲染效果的常见错误。 避免常见错误 - 提升渲染游戏的技巧 在追求创建真正逼真的…...

fastadmin采坑之获取当前登录admin用户的信息

在controller层里想要获取当前登录admin用户的信息 print_r($this->auth->getUserInfo());但是有个问题 我在fa_admin表中添加了新的字段&#xff0c;这个方法获取不到新字段的数值&#xff0c;具体也没有去研究估计跟方法有关 然后我直接用模型去获取数据&#xff0c;简…...

【Spring AOP + 自定义注解 + 动态数据源 实现主从库切换读写分离】—— 案例实战

&#x1f4a7; S p r i n g A O P 主从数据源切换 读写分离 自定义注解案例实战&#xff01; \color{#FF1493}{Spring AOP 主从数据源切换 读写分离 自定义注解 案例实战&#xff01;} SpringAOP主从数据源切换读写分离自定义注解案例实战&#xff01;&#x1f4a7; …...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...