依赖注入实现原理

news2024/12/28 1:58:17

依赖注入实现原理

一、@Autowire

流程图:
在这里插入图片描述

在这里插入图片描述

@Autowire的后置处理器类是AutowiredAnnotationBeanPostProcessor,在启动时会执行这里面的方法

步骤一:寻找注入点

在这里插入图片描述

在创建一个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对于的注入点集合对象,并缓存。
步骤二:遍历注入点

在这里插入图片描述

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. 利用反射将找到的所有结果对象传给当前方法,并执行。
步骤三:根据注入点类型找Bean

在这里插入图片描述

findAutowireCandidates()实现

  1. 找出BeanFactory中类型为type的所有的Bean的名字,注意是名字,而不是Bean对象,因为我们可以根据BeanDefinition就能判断和当前type是不是匹配,不用生成Bean对象
  2. 把resolvableDependencies中key为type的对象找出来并添加到result中
  3. 遍历根据type找出的beanName,判断当前beanName对应的Bean是不是能够被自动注入
  4. 先判断beanName对应的BeanDefinition中的autowireCandidate属性,如果为false,表示不能用来进行自动注入,如果为true则继续进行判断
  5. 判断当前type是不是泛型,如果是泛型是会把容器中所有的beanName找出来的,如果是这种情况,那么在这一步中就要获取到泛型的真正类型,然后进行匹配,如果当前beanName和当前泛型对应的真实类型匹配,那么则继续判断
  6. 如果当前DependencyDescriptor上存在@Qualifier注解,那么则要判断当前beanName上是否定义了Qualifier,并且是否和当前DependencyDescriptor上的Qualifier相等,相等则匹配
  7. 经过上述验证之后,当前beanName才能成为一个可注入的,添加到result中
步骤四:处理多个bean
步骤五:多个bean的判断
步骤六:反射注入值

在这里插入图片描述

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

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

相关文章

单片机原理及应用:独立式键盘控制LED与多功能按键识别

今天来介绍另一个外设——按键与LED的配合工作,与开关不同,按键需要注意消除抖动带来的影响,代码逻辑也会更复杂一写,下面先为大家介绍独立式键盘的相关知识。 单片机的独立式键盘指的是一种不依赖于计算机或其他外部设备的键盘输…

数据结构:堆的三部曲(二)top K问题

堆的应用(一)top K问题 一.top k问题的应用本质解析二.top K问题使用案例——从100亿整型的文件中找出前5个最大值1.建堆1.1过程分析1.2过程图模拟1.3向上调整算法代码1.4建堆代码 2.处理文件中剩余剩余元素2.1过程分析2.2过程图示例2.3向下调整算法代码…

百度百科词条创建多久可以通过?

一个优质的百度百科词条,能提升个人或企业的品牌形象。因此,越来越多的人希望创建自己的百度百科词条,那么,创建一个百度百科词条到底需要多久才能通过审核呢?接下来伯乐网络传媒就来给大家分享一下。 一、百度百科词条…

AI计算,为什么要用GPU?

今天这篇文章,我们继续来聊聊芯片。 在之前的文章里,小枣君说过,行业里通常会把半导体芯片分为数字芯片和模拟芯片。其中,数字芯片的市场规模占比较大,达到70%左右。 数字芯片,还可以进一步细分&#xff0…

灰度发布及声明式资源管理(yaml文件)

一、三种常见的项目发布方式 1)蓝绿发布 2)灰度发布【常用】 3)滚动发布 应用程序升级,面临最大的问题是新旧业务之间的切换 立项-定稿-需求发布-开发-测试-发布,测试上线后,再完美也会有问题,为…

【Mybatis】深入学习MyBatis:高级特性与Spring整合

🍎个人博客:个人主页 🏆个人专栏: Mybatis ⛳️ 功不唐捐,玉汝于成 目录 前言 正文 高级特性 1 一级缓存和二级缓存 一级缓存 二级缓存 2 延迟加载 5 整合Spring 1 MyBatis-Spring模块 2 事务管理 结…

C#基础:字段的初始化、继承

一、字段的初始化 class Test {static int Main(string[] args){var list new List<Calculate>();//1.Calculate中加入abvar calculate new Calculate { a 2, b 3 };//2.Calculate中加入Value列表calculate.Values.Add(new Value { id 1, value 6 });calculate.Va…

计算机组成原理-期末复习

目录 第一章——计算机系统概述 一、数字计算机的主要组成结构 二、指令的形式 三、控制器的基本任务 四、指令流和数据流 五、适配器与输入/输出设备 七、计算机的系统软件 八、C 语言的转换层次图 九、计算机系统的层次结构图 第二章——运算方法和运算器 一、 数据格式…

MySQL之表的记录操作

前言 存数据不是目的&#xff0c;目的是能够将存起来的数据取出来或者查出来&#xff0c;并且能够对数据进行增删改查操作&#xff0c;本文将详细介绍表中记录的增删改查操作。对记录的操作属于DML数据库操作语言&#xff0c;可以通过SQL实现对数据的操作&#xff0c;包括实现向…

爬虫入门与urllibrequests

前情摘要 一、web请求全过程剖析 我们浏览器在输入完网址到我们看到网页的整体内容, 这个过程中究竟发生了些什么? 我们看一下一个浏览器请求的全过程 接下来就是一个比较重要的事情了. 所有的数据都在页面源代码里么? 非也~ 这里要介绍一个新的概念 那就是页面渲染数据的…

爬取涛声网音频

代码展现&#xff1a; 代码详情&#xff1a; import requests import re import os filename 声音// if not os.path.exists(filename): os.mkdir(filename) def down_load(page): for page in range(page): page page1 url https://www.tosound.…

如何将图像数据转换为.mat文件,mat文件内是cell封装的struct格式的数据

在我看论文&#xff1a;《 Holistically-nested Edge Detection (HED) 》的时候&#xff0c;对论文中有关边缘结果的评价指标很感兴趣&#xff0c;于是我就研究了如何计算这些指标 如果有同样感兴趣或者有需要的小伙伴可以下载这里的代码&#xff1a;GitHub - xwjabc/hed: A P…

IO进程线程 day4 文件IO与目录操作

1.使用标准IO完成两个文件拷贝 #include <head.h> int main(int argc, const char *argv[]) {//判断输入是否合法if(argc>3){printf("输入不合法\n");return -1;}//定义两个文件指针&#xff0c;用于读写FILE *fp1NULL;FILE *fp2NULL;if((fp1fopen(argv[1]…

扩展:键盘录入笔记(next()、nextLine()、nextInt()、nextDouble())

文章目录 一&#xff0c;键盘录入涉及到的方法如下&#xff1a;1&#xff09;next&#xff08;&#xff09;、nextLine&#xff08;&#xff09;&#xff1a;代码示例&#xff1a;代码示例&#xff1a; 2&#xff09;nextInt&#xff08;&#xff09;&#xff1a;代码示例&…

面试题:Linux命令大全

序号命令对应英文作用1ls [目录名]list查看当前目录下的内容2pwdprint work directory查看当前所在目录3cd [目录名]change directory切换目录4touch [文件名]touch如果文件不存在,创建文件5mkdir [目录名]make directory创建目录6rm [文件名]remove删除指定文件 ls 查看当前目…

hAdmin漂亮的后台html模板免费下载

hAdmin漂亮的后台html模板免费下载-遇见你与你分享

Qt6.5类库详解:QFontComboBox

哈喽大家好&#xff0c;欢迎关注公众号(20YC编程)&#xff0c;有免费视频课程哦&#xff01; -今日内容- 1 QFontComboBox介绍 QFontComboBox是Qt框架中的一个字体选择类&#xff0c;它提供了一个下拉列表框&#xff0c;用于选择字体。 QFontComboBox的主要功能和特点&#x…

Java基础-----集合类(四)

文章目录 1. Iterator和ListIterator1.1 简介1.2 常用方法 2. remove方法2.1 比较foreach方式和迭代器方式删除元素2.2 找原因 -- 迭代器删除操作源码 1. Iterator和ListIterator 1.1 简介 1.Iterator 可以遍历List集合&#xff0c;也可以遍历Set集合&#xff1b; ListIterat…

Unity SVN更新提交小工具

Unity SVN更新提交小工具 前言使用说明必要前提源码参数说明 感谢 前言 Unity开发时每次都要到文件夹中操作SVN&#xff0c;做了一个小工具能够在Editor中直接操作。 使用说明 必要前提 前提是要安装好SVN&#xff0c;在文件夹右键能够看到安装的SVN 源码 using System…

音效出众设计时尚,内置AI功能,sanag塞那Z50上手

现在蓝牙耳机已经成为人们生活中不可或缺的一部分了&#xff0c;像是在上班、坐车的时候&#xff0c;既可以享受自己的音乐空间&#xff0c;又不会吵到别人&#xff0c;看书、做题还是运动的时候&#xff0c;也可以保证长时间使用耳朵卫生、舒适度。正因为庞大的市场需求&#…