Spring源码分析之依赖注入(一)

Spring Boot 注解之ObjectProvider源码追踪 最近依旧在学习阅读Spring Boot的源代码,在此过程中涉及到很多在日常项目中比较少见的功能特性,对此深入研究一下,也挺有意思,这也是阅读源码的魅力之一。这里写成文章,分享给大家。 自动配置中的ObjectProvider 在阅读Spring Boot自动配置源码中关于Tomcat的配置时,看到这样如下的自动配置配置源代码。 @Configuration(proxyBeanMethods =... 阅读详情

一、前言

主要讲解了在依赖注入过程中, 注入点的获取和属性的注入。

二、前置学习

依赖注入的几种方式

@Bean注解注入(已废弃)

使用以下这种方式去注入, 源码分析会用到

自动注入

源码位置

实例化Bean方法: AbstractAutowireCapableBeanFactory.doCreateBean(), 在这个方法里面有一个属性填充的方法:

doCreateBean没印象或者不知道的, 建议从头开始看源代码, 从头走一遍, 才更清晰明了

点进去, 这个方法就是依赖注入相关源代码

三、@Bean注解注入分析

在我们的源码方法 populateBean里面, 有一段这样的代码

如果我们使用 @Bean(autowire = Autowire.BY_TYPE) 这种方式去注入的话, 那么就会进入上图中红框位置的 if判断

AUTOWIRE_BY_NAME

假设我们使用的是 @Bean(autowire = Autowire.BY_NAME)方式, 那么就会进入以下方法

unsatisfiedNonSimpleProperties方法

在上面的 autowireByName方法中, 又是通过了 unsatisfiedNonSimpleProperties(mbd, bw);方法去获取 Bean中能进行自动注入的属性名, 我们进入这个方法看一下

其中画红框的, 叫做属性描述器, 是由java.beans提供的, 在这里获取当前 Bean的类里面具体的属性和其getter, setter方法

当一个属性是 private作用域且有对应的 getter和 setter方法, 那么 java就认为他是一个真正的属性

接下来的流程判断什么样的属性能进行自动注入?:

  • 该属性有对应的set方法
  • 没有在ignoredDependencyTypes中
  • 如果该属性对应的set方法是实现的某个接口中所定义的,那么接口没有在ignoredDependencyInterfaces中
  • 属性类型不是简单类型,比如int、Integer、int[]

简单类型如下图所示

进入循环

执行完 unsatisfiedNonSimpleProperties方法获取到当前 Bean中能进行自动注入的属性名之后进入循环遍历

进入这个循环之后的简单流程如下:

  • 通过注入属性的名字去 getBean, 获取 bean对象
  • 将对象加到 MutablePropertyValues集合中
  • 记录一下propertyName对应的Bean被beanName给依赖了

AUTOWIRE_BY_TYPE

AUTOWIRE_BY_TYPE实际上和 AUTOWIRE_BY_NAME是一样的流程, 代码就不详细说明了, 流程如下:

  • 找出 setter对应的属性名
  • 遍历
  • 把对象找出来
  • 找出当前属性描述器对应的类型
    • 找参数的类型
  • 调用resolveDependency方法找到对象
  • 将对象加到 MutablePropertyValues集合中
  • 记录一下propertyName对应的Bean被beanName给依赖了

resolveDependency方法是比较重要的, 后续会专门讲一下

代码如下图所示:

四、处理 @Autowired, @Resource等注解

如图所示, 我们是执行了第二个红框内的方法去处理 @Autowired, @Resource等注解的, 通过上面第一个红框也可以看到, 他具体是通过后置处理器来实现的

我们进入第一个红框内的 InstantiationAwareBeanPostProcessor接口, 去看他具体的实现

在上图中

  • 红框一的那个实现类, 是处理 @Autowired和@Value注解的
  • 红框二的那个实现类, 是处理 @Resource注解的

寻找注入点

我们进入 AutowiredAnnotationBeanPostProcessor类中

在这个类里面有一个 postProcessMergedBeanDefinition方法

通过之前看源码的可知, 我们会先执行postProcessMergedBeanDefinition这个方法, 继续看里面的方法

根据当前 Bean的类去找注入点(属性或者某个方法上面加了 @Autowired注解), 具体方法是 buildAutowiringMetadata(clazz);

点进这个方法内部

判断当前类需不需要找注入点

例如: 如果一个Bean的类型是String, 那么则根本不需要进行依赖注入

这个方法里面就是各种方法跳转, 就不贴图了, 最后会进入下面这个方法, 大概意思是如果类名字是以 java. 开头的话就不用找注入点了

遍历当前 Bean所有的字段

这里有一个lambda表达式, 他会去判断field上是否存在@Autowired、@Value、@Inject中的其中一个, 具体实现如下

如上图所示, 他会遍历一个 autowiredAnnotationTypes的 Set集合, 这个列表所属的类有一个构造方法, 在构造方法的内部为这个集合添加了 @Autowired注解和 @Value注解

在上图的 findAutowiredAnnotation()方法中, 它会去遍历当前类上的所有注解, 有没有刚刚配置在 Set集合中的注解

static不进行注入

如图所示, 需要注意的是, 如果当前的属性是 static的, 那么直接return掉, 不进行属性的注入

为什么一个字段是static的, 不将其当做注入点

如果我们的 Bean对象不是单例的, 而是多例或者其他类型的, 那么获取一次Bean都会将其重新创建一遍, 这不符合我们对 static静态资源的预期

如果获取到相关的注解

如果获取到相关的注解了, 那么继续往下走,会先执行一个方法, 然后把当前这个字段设置为一个注入点

在我们的 @Autowired注解中, 可以进行配置 required, 这个值默认是true的, 他的含义是: 如果在依赖注入的时候, 没有找到这个 Bean是会报错的, 如果设置为 false之后, 在依赖注入期间没有找到这个 Bean就不会报错了

下面的代码, 就是对 @Autowired注解属性配置的单独处理

boolean required = determineRequiredStatus(ann);
复制代码

遍历当前 Bean所有的方法

接着往下走, 就是遍历当前 Bean所有的方法了

还是一样的, 简单流程如下:

  • 过滤掉桥接方法
  • 去找方法上面有没有加注解
  • 是不是静态方法
  • 某个方法的参数等于0, 则打印日志
  • 解析 required值
  • 封装成AutowiredMethodElement类
  • 当成注入点加入 currElements集合中

桥接方法, 是专门用来处理一些特殊的情况的

如下图所示, 如果是用以下这种方式编写代码, 那么在字节码文件中就会发现两个 setOrderService方法, 这个时候就需要桥接方法帮助我们找到原方法

遍历父类, 去循环上面的操作

注意, 我们这个方法是一个 do while循环, 先执行当前 Bean再去遍历 父Bean

return

将当前类和父类的注入点都找出来, 封装成一个对象, 把这个对象返回并且缓存, 存到外面的方法

返回到上一个方法, 可以看到, 已经将返回值缓存到了 injectionMetadataCache中

注入点进行注入

根据我们之前进行 Bean生命周期的分析, 接下来会执行 postProcessProperties方法

取出注入点

在这个方法的第一行代码, 就是取出注入点, 具体代码如下所示, 之前已经全部注入完了, 这里就不详细讲了

给注入点进行注入

如下图所示, 接下来获取到所有的注入点, 然后对其进行遍历

遍历的 InjectedElement类, 是一个父类, 他的具体实现, 通过下图可以看到, 分别是方法和字段

注意, 这里查看具体处理方法的时候, 不要直接点进 element.inject(target, beanName, pvs);方法, 因为我们是子类继承父类去实现的, 所以要去找子类的实现方法

字段的注入实现

流程简单说明:

  • 找出注入点封装的字段
  • 获取字段的对象
  • 获取缓存, 我们没有, 直接进入else
  • 调用方法 resolveFieldValue
    • 根据字段的类型, 名字去找具体的值(下一篇文章详细讲解)
  • 找到之后通过反射为字段复制

字段的注入实现代码如下图所示:

方法的注入实现

流程简单说明:

  • 如果pvs中已经有当前注入点的值了,则跳过注入
  • 找出方法对象
  • 获取缓存, 我们没有, 直接进入else
  • 根据 @Autowired注解的参数返回对象数组
  • 执行 method.invoke(bean, arguments);

方法的注入实现代码如下图所示:

五、属性注入方法的执行

回到我们本标题的最开始, 看这个for遍历, 如下图所示

在这个遍历过程中, 我们可以看到它执行了一个我们所熟悉的方法, 属性的注入

六、属性赋值

可以看到, 在上面的代码分析过程中, 并没有实际的做属性赋值操作, 那么具体的属性赋值实际上是在该方法的最后一行

这个方法实际上就是将 BeanDefinition中的属性和值设置到 Bean对象中, 感兴趣的可以去看一下

树莓派4B(Raspbian buster系统)安装ROS Melodic(附带网络配置和远程桌面控制说明) 树莓派4B(Raspbian buster系统)安装ROS Melodic(附带网络配置和远程桌面控制说明) 一、硬件准备 二、软件准备 三、安装前的准备工作 四、开始ROS的安装 五、运行小乌龟 由于坑比较多希望大家安装的时候尽量不要跳步进行,一定要等每一步运行成功了再往下进行。 一、硬件准备 1、树莓派4B一个 2、SD卡一张(最好是16G以上的我的是用的64G的) 3、显示器、键盘、鼠标 二、软件准备 1、Raspberryimage (写系统使用的) 链接:https://pan.baidu.com 阅读详情

相关推荐

MIPI转LVDS芯片调试实战:从Kernel到UEFI的完整点亮流程

本文详细解析了MIPI转LVDS芯片调试的全流程,从Kernel驱动开发到UEFI早期初始化,涵盖I2C通信、电源时序控制等核心挑战。通过LT9211芯片实战案例,提供设备树配置、电源时序优化及显示异常排查等实用技巧,助力工程师高效完成屏幕调试工作。

weixin_30314813的博客 452

Spring 依赖注入源码

Spring早期依赖注入的两种方式:BY_NAME 和 BY_TYPE寻找所有的注入点,为注入点赋值,入口处理@Value注解,根据type,然后遍历所有的BeanDefinition,找到匹配的beanName集合。判断1,处理@Bean注解的autowireCandidate=false,判断BeanDefinition中的autowireCandidate属性值判断2,处理泛型的情况判断3,处理@Qualifier注解,

qq_44027353的博客 1329

双目相机立体匹配算法概述(含Python代码)

立体匹配任务是计算机视觉中的一个重要问题,旨在从一对具有相同场景的图像中估计每个像素的视差(disparity)。本文对现有的传统算法和深度学习算法进行了综述,以便于各位选择合适的立体匹配算法用于深度估计或三维建模。

m0_59257547的博客 8294

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

Spring之依赖注入源码解析

持续学习,坚持原创,分享技术笔记及经验。 736

嵌套交叉验证的‘双循环’哲学:为什么你的模型评估总是不准?

本文深入探讨了嵌套交叉验证(Nested Cross-Validation)在机器学习模型评估中的关键作用,揭示了传统交叉验证方法存在的偏差问题。通过双重循环设计,嵌套交叉验证有效隔离数据,提供无偏评估,显著提升模型在真实场景中的性能预测准确性。文章还提供了工程实践中的优化策略和量化分析,帮助开发者在计算成本与评估精度之间找到平衡。

b3n4m5q6w7的博客 225

LangChain Message 官方文档

消息是聊天模型中的基本通信单位。它们用于表示聊天模型的输入和输出,以及与对话相关的其他上下文或元数据。每条消息都包含一个角色(如“用户”、“助手”)和内容(如文本或多模态数据),并可能包含根据不同聊天模型提供商而有所不同的附加元数据。LangChain 提供了一个统一的消息格式,可以跨不同聊天模型使用,简化用户在不同模型之间切换时所需关注的消息格式差异。

AI Agent 首席体验官 896

Spring源码之依赖注入

Spring在依赖注入前,会调用Bean的后置处理器,把所有注入点提前找到缓存起来.这里使用到的后置处理器就是AutowiredAnnotationBeanPostProcessor,我们来看关键的方法beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);首先根据前面的知识,我们知道Spring Bean的依赖注入是在Bean实例化后,根据下列调用链路,我们找到具体逻辑执行的地方.

2302_77659577的博客 404

ADS学习笔记 1. 功率放大器设计

基于ADS2023 update2的学习笔记1.功率放大器设计

u014087103的博客 1万+

Spring依赖注入源码分析

Spring的核心之一就是依赖注入,Spring提供了@Autowired注解来给bean注入依赖。除了注入最基本的bean之外,Spring还做了一些扩展,例如你可以注入Optional,以此来判断依赖的bean是否存在;你还可以注入Map来获得所有候选的bean;当然了List和Set自然也是支持的。Spring依赖注入是怎么实现的呢?

程序员小潘 1222

SCL3400-D01双轴高精度倾角计

简介 两轴高精度加速度计,提供两个模式。 ±30° with 10 Hz LPF ±90° with 40 Hz LPF Resolution up to 32768 LSB/g Ultra-low 0.0009°/√Hz noise density 这款传感器是替换之前村田的停产的模拟量系列的芯片,正在测试中,具体效果大伙可以评测。 一、引脚连接图 引脚图兼容SCL3300 二、SPI接口 1.SCL3300和SCL3400略有区别如下图 左边为SCL3...

专注惯导领域 3808

电动汽车远程监控与诊断软件:BMW ConnectedDrive EV远程监控二次开发_7.数据安全与隐私保护

数据加密是保护数据安全的重要手段之一。在电动汽车远程监控与诊断软件中,加密技术可以确保数据在传输过程中的安全性和完整性。常见的加密技术包括对称加密和非对称加密。

zhubeibei168的博客 884

Spring之依赖注入源码解析

Spring的依赖注入(Dependency Injection,DI)是Spring框架核心的一部分,它是实现控制反转(Inversion of Control,IoC)的一种方式。依赖注入可以帮助我们减少代码的耦合度,提高模块间的独立性和可测试性。Spring框架的依赖注入主要发生在Spring容器初始化应用上下文时。

weixin_44906791的博客 1041

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

【Spring源码分析】从源码角度去熟悉依赖注入(一)

咱说的依赖注入在生命周期就是对应着属性注入的阶段,其中有在自定义MergedBeanDefinitionPostProcessor中手动设置属性值,和设置对应的是BYTYPE还是BYNAME,还有种就是注解的解析了。前俩者就是去找对应的setter方法,后面注解的形式是通过反射的注入..................

qq_63691275的博客 1276

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

spring5源码分析系列(七)——基于XML的依赖注入(一)

    前言:前面系列文章分析了Spring IOC容器的初始化过程,接下来分析Spring的依赖注入。 1.依赖注入发生的时间     当Spring IOC容器完成了Bean定义资源的定位、载入和注册以后,IOC容器中已经管理Bean定义的相关数据,但是此时IOC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况发生: (1)用户第一次通过getBean方法向IOC容索要Bean...

yaofengdoit的博客 186

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Spring5源码分析(三) IOC容器的依赖注入—基于XML的依赖注入(一)

Spring中IOC容器的依赖注入主要有两种方式,一种是基于XML的依赖注入,一种是基于Annotation的依赖注入。接下来将对这两种依赖注入的方式进行分析,依赖注入的代码也比较复杂,所以还是分成几篇进行讲解。 一、依赖注入发生的时间   当 Spring IOC容器完成了Bean定义资源的定位、载入和解析注册以后,IOC 容器中已经管理类Bean定义的相关数据,但是此时IOC容...

mokingone的专栏 700

Spring源码之解析属性进行依赖注入(十)

最近准备把spring,springmvc,mybtais,springboot,部分的cloud组件的源码重头梳理一下,并在语雀记录一下。 Spring源码之解析属性进行依赖注入(十) https://www.yuque.com/dalianpai/spring/gsd5t1 ...

qq_29860591的博客 257

Spring @Autowird注解和@Resouce注解源码分析

从使用上来看@Autowird和@Resource注解的区别 两个注解都可用于属性或者方法上的注入;@Autowired是默认按照类型装配, @Resource默认是按照名称装配 从提供来源看: @Autowired是由Spring提供 @Resource是有java提供,在包javax.annotation下 从spring处理源看: @Autowired是由AutowiredAnnotationBeanPostProcessor后处理器进行处理 @Resource是由CommonAnnotat

持之以恒 718

spring中@Autowired注解的原理

阅读代码我们可以看到,Autowired注解可以应用在构造方法,普通方法,参数,字段,以及注解这五种类型的地方,它的保留策略是在运行时。在Spring源代码当中,Autowired注解位于包org.springframework.beans.factory.annotation之中,如上图。...

m0_46420244的博客 4944

个人spring见解指南

spring来管理,通过各种各样的手段也就是模式,汇集到spring容器池里面去,在这个容器池里有一个大的集合,大集合里有小集合,像是一个List<map<k,v>>.的形式.然后spring又通过各种各样的手段如代理,去这个池子里去拿Bean,每个Bean的话都由@Compent,这样类似的注解来去找spring注册,注册好后就形成了xml中的文件,或者就没形成,直接组装成数据在一个特定的容器中供它调用,这个容器有自己的标识定位.从而来达到某种类似xml被dom4j等解析类解析使用

shizhon5666的博客 113

Spring源码系列(一)你真的理解Spring的自动注入吗?

Spring的自动注入,我想任何一个Java的程序员都会无比的自信的说:这个我知道;但是很遗憾的说,笔者理解的自动注入可能与你们理解的自动注入有很大的出入。那我们需要搞清楚Spring的自动注入是什么?自动注入也可以叫自动装配。只是翻译不同,笔者的英文水平有限,这儿就叫自动注入吧!自动注入的对立面就是手动装配。在Spring的程序中,假设你有个A类依赖了B类,这个时候需要在A类添加一个B类的属性。再加上set方法。然后在xml的配置文件中,描述对应的依赖关系。这个时候IOC容器初始化的过程中会实例化A,在实

二狗家有矿 344

Spring源码之依赖注入(一)

前面我们已经分析完了Bean的生命周期,包括BeanDefinition的扫描与注册,Bean的初始化和销毁等。今天就来分析依赖注入(DI)相关的源码。依赖注入: Dependency Injection,它是 spring 框架核心 IOC 的具体实现,具体点就是依赖关系的维护称之为依赖注入。我们的程序在编写时, 通过控制反转(IOC), 把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。IOC 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。

qq_43456605的博客 1279

Spring源码分析の依赖注入(@AutoWired模式)

在Spring中,进行依赖注入最常见的方式是@AutoWired和@Resource。其中默认按类型(byType)查找,如果找到多个匹配的Bean,则按名称(byName)查找。而@Resource是先根据名称查找,如果(根据名称)查找不到,再根据类型进行查找。@AutoWired在源码中的体现,主要在于:在实例化后,依赖注入前预先寻找注入点在实例化后,初始化前,进行注入Spring 在实例化后,初始化前,扫描标记了该注解的属性或者方法,作为注入点缓存。

西岭千秋雪的博客 1293

spring依赖查找、依赖注入深入学习及源码分析

延迟查找,我个人认为主要是给架构开发者使用的。非常典型的一个使用场景,就是SpringBoot里的自动配置,可以看看LettuceConnectionConfiguration这个类,这个类用于创建RedisClient。显然,RedisClient的创建是要根据用户的需求来创建的。有些属性是必须的,可以在配置文件里配置,比如ip,port这种。Lettuce在创建RedisClient的时候,会从配置文件里读取这些数据来创建RedisClient。

秃了也弱了 1409

Spring源码分析 IOC依赖注入

Spring源码分析 IOC依赖注入 1 基于上篇 Spring源码分析 Bean创建和获取 依赖注入是在beaa创建时候完成,bean的创建触发过程如下 单例模式非延迟加载的对象,会在IOC容器初始化的时候被创建且初始化 非单例模式或者延迟加载的对象,应用第一次向容器索要该Bean对象的时候被创建且初始化 基于创建bean源码分析IOC依赖注入 public Object getBean(...

zahary 346

Spring依赖注入——逐行源码分析

Spring依赖注入

qq_44027353的博客 1057
上一篇: Spring源码分析之依赖注入(二)
下一篇: 分布式事务调优
java_lujj
博客等级 码龄4年 18粉丝 152原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值