作者:编程新说李新杰

出自:微信公众号“编程新说”

原文:品Spring:对@Autowired和@Value注解的处理方法


在Spring中能够完成依赖注入的注解有JavaSE提供的@Resource注解,就是上一篇文章介绍的。

还有JavaEE提供的@javax.inject.Inject注解,这个用的很少,因为一般都不会去引用JavaEE的jar包。

编程新说注:JavaEE早已经被Oracle抛弃了。JavaEE这个名字已经成为历史。

还有两个就是@Value和@Autowired注解,这可是Spring自己的亲孩子。所以这两个使用的最多。

虽然注解不一样,但是目的一样,都是用来进行依赖注入,而且Spring处理依赖注入都是用的一个套路。

在上一篇文章中已经说的很详细了,这里再说一遍,就当巩固了。

从最通俗的角度来说,依赖注入就是这样的:

首先,要知道谁需要被注入。用A表示。

其次,要知道把谁注入。用B表示。

再者,从容器中找到它。用find(B)表示。

最后,完成注入动作。用<-表示。

因此,整个过程可以用一个式子表示:

A <- find(B)

Spring采用的统一方案如下:

1)找出一个类中需要被注入的元素,其实就是字段和方法,然后使用InjectedElement和InjectionMetadata来表示。

2)找出需要注入什么类型的对象,其实就是字段类型和方法参数类型,然后使用DependencyDescriptor来表示。

3)根据第2步的描述,从容器中找到(解析出)这个对象,这由容器负责,beanFactory.resolveDependency(..)。

4)完成具体注入动作,就是把第3步的值应用到第1步里,是字段的话就是设置一下,是方法的话就调用一下。

这是依赖主人的宏观过程,但是对不同的注解,有些细节性的东西是不同的。下面一起来看下。

被注入元素

如果被注入的是一个字段,如下图01:

表示字段的值是否必须被注入,还有缓存字段的值。

如果被注入的是一个方法,如下图02:

表示方法的参数值是否必须被注入,还有缓存方法的参数值。

编程新说注:这里缓存的字段值和方法参数值,并不是一个具体的值,只是一个依赖描述(DependencyDescriptor)。稍后会看到。

依赖的描述

Spring对@Autowired的处理是按类型进行的,所以必须按类型过滤容器中的所有bean,这样效率会低一些。

所以当过滤到这样的bean之后,就会缓存下bean的名称,下次就直接用这个bean名称去找,就会很快了。

这就涉及到对依赖描述的扩展,如下图03:

这里把bean的名称和类型都记录下来,下次直接进行短路操作,使用getBean(..),不用再遍历了。

从容器中解析出依赖

对字段来说,如下图04:

使用Field生成一个依赖描述,然后去容器中解析出能够和字段类型兼容的所有bean,并把bean名称放入autowiredBeanNames这个Set中去。

然后进行缓存,如下图05:

主要缓存了bean名称,在下次再装配时,进行短路操作。

对于方法来说,如下图06:

由于方法有多个参数,每个参数都需要依赖,所以就按参数逐个处理。

使用Method和参数索引生成一个MethodParameter,然后再用它生成依赖描述。

然后去容器中解析出能够和该方法参数类型兼容的所有bean,并把bean名称放入autowiredBeans这个Set中去。

然后再进行缓存,如下图07:

依赖的注入

对于字段,调用set方法,如下图08:

对于方法,调用invoke方法,如下图09:

以上就是具体的处理过程和对通用处理的扩展。

这里面似乎有一个问题,就是对@Autowired的处理和@Value的处理应该是不太相同的,但是上述过程中并没有体现。

这一部分其实是交给了容器去处理了,在beanFactory.resolveDependency(..)这个解析依赖的方法里进行了处理。

对构造方法的处理

构造方法是很特殊的,在容器准备实例化一个bean时,就会去找出一个最合适的构造方法,然后通过反射调用它来生成一个对象。

如果一个类定义了多个构造方法,Spring会通过一个复杂方式从中选出一个最合适的。

由于@Autowired注解可以作用于构造方法上,所以可以用它来适当改变Spring的这种选择方式。

把@Autowired注解标到其中几个构造方法上,这样Spring只会在这些标注解的之间进行选择,相当于起一个收窄作用。

此时还会把默认无参的构造方法也作为备选,因为标注解的都不能满足的话,就只能使用默认的。

如果一个类有多个构造方法,但我们想非常明确的使用某一个,那就把@Autowired标在它上,并把注解的required属性设置为true。

这样只会把这一个选出来,此时不会再考虑默认无参的构造方法。相当于起一个特指作用。

编程新说注:这个特指作用的用法和上面那个收窄作用的用法不能混合使用,只能二选一,否则报错。

这就是@Autowired注解对构造方法的作用。

和bean后处理器的结合

构造方法的处理逻辑是在determineCandidateConstructors这个方法里调用的,目的是给我们一个决定构造方法的机会,如果决定不出来也不要紧,Spring还会自己决定。

剩下的就和之前的一样了,在postProcessMergedBeanDefinition方法里准备好和依赖注入相关的元数据。

在postProcessProperties方法里,根据元数据从容器中解析出依赖并完成注入动作。


Spring系列资源合集

Java基础、入门、精通、架构师全套资源​shimo.im

推荐阅读:

java钢铁侠-马克51号:我们还需要学jQuery吗?(文末附jQuery视频教程)​zhuanlan.zhihu.com

@autowired注解_品Spring:对@Autowired和@Value注解的处理方法(文末附spring系列资源合集)...相关推荐

  1. 【spring容器启动】之bean的实例化和初始化(文末附:spring循环依赖原理)

    本次我们通过源码介绍ApplicationContext容器初始化流程,主要介绍容器内bean的实例化和初始化过程.ApplicationContext是Spring推出的先进Ioc容器,它继承了旧版 ...

  2. 罗马音平假名片假名转换器_关于五十音你所要知道的一切!文末附日网高清字帖...

    今天开始,木子小花日本语教室将开始同时更新日语文法系列文章 和 日语真题详解系列文章,从五十音图的记忆方法到日语助词的用法整理,从N5的简单句子构成到N1复杂文法的接续记忆方法,力求做出全知乎(小声: ...

  3. python入门应该学什么专业好_真的能半个月学会Python吗?(文末附python入门进阶教程)...

    这里为什么用 Python 举例呢? 因为在很多人看来,Python 比较"简单". 写这篇文章主要是因为我在知乎上看到了一条有趣的动态: 该条动态的作者认为一个高考600分以上的 ...

  4. 分类算法python程序_分类算法——k最近邻算法(Python实现)(文末附工程源代码)...

    kNN算法原理 k最近邻(k-Nearest Neighbor)算法是比较简单的机器学习算法.它采用测量不同特征值之间的距离方法进行分类,思想很简单:如果一个样本在特征空间中的k个最近邻(最相似)的样 ...

  5. 怎么实现注解_通透!一口气搞懂注解到底怎么用

    日志脱敏场景简介 在日志里我们的日志一般打印的是 model 的 Json string,比如有以下 model 类 public class Request { /** * 用户姓名 */ priv ...

  6. 自定义JAVA注解_深入理解Java:自定义java注解

    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解: 元注解的作用就是负责注解其他注解.Java5. ...

  7. java nullable注解_【Java】idea @NotNull @Nullable 注解

    这两个注解在idea里面可以帮助我们检测方法的返回值,方法参数以及局部变量是否为空,从而帮助我们减少一些NPE的发生. 1. 原始注解 @NotNull @Nullable最开始只能使用idea提供的 ...

  8. python识别手写文字_如何快速使用Python神经网络识别手写字符?(文末福利)

    原标题:如何快速使用Python神经网络识别手写字符?(文末福利) 点击标题下[异步社区]可快速关注 在本文中,我们将进一步探讨一些使用Python神经网络识别手写字符非常有趣的想法.如果只是想了解神 ...

  9. @param注解_启用 parameters 编译选项简化 mybatis @Param 注解重复问题

    在使用 mybatis 查询的时候, 只需要定义一个查询接口, mybatis 会为我们注入注解实现或是 xml 实现. 但当我们需要传递参数时, 通常需要 @Param 来定义一个名称, 但经常的, ...

最新文章

  1. Swift 学习手记1,pod 的 类库使用
  2. java实用教程——组件及事件处理——布局的一个小实例
  3. lintcode循环数组之连续子数组求和
  4. python 数据清洗 豆瓣电影_Python高阶操作--关于数据清洗
  5. 直播项目之仿全民TV(已开源)
  6. 理解Visual Studio 解决方案文件格式(.sln)
  7. Gradle 配置 BuildConfig详解
  8. php 如何滑动,php 滑动门切换代码示例
  9. tuio+ 图片拼接软件制作方法
  10. noteexpress选择网页作为题录的使用方法
  11. 01英语语法-基本句型及补语
  12. 环比计算分母为0怎么办?
  13. 数据的更新(update的用法)笔记
  14. 美妆行业如何在小红书营销推广?美妆品牌的线上推广怎么宣传更有效果?
  15. 2021长安杯再做--wp
  16. C# 定时器轮询 设计思路
  17. 西瓜播放器 vue+xgplayer播放mp4/hls视频流。
  18. 一个承载无数悲痛的网站
  19. 直播弹幕系统(五)- 整合Stomp替换原生WebSocket方案探究
  20. 开启前端CSS学习之路-css003

热门文章

  1. 【微软出品】AI-神经网络基本原理简明教程
  2. 全网最火的Nacos源码构建,你找不到第二个有我仔细的!!
  3. k-近邻算法之距离度量
  4. 求相关和卷积的full和same
  5. 如何更改linux文件目录拥有者及用户组
  6. C语言借助两个数的大小交换,引入指针。
  7. ECCV 2020 Oral | 可逆图像缩放:完美恢复降采样后的高清图片
  8. 第五篇:协调和协定之选举算法
  9. 双调TSP问题通俗讲解
  10. 第十二周-学习进度条