品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系列文章 <<<
品Spring:SpringBoot和Spring到底有没有本质的不同?
品Spring:SpringBoot轻松取胜bean定义注册的“第一阶段”
品Spring:SpringBoot发起bean定义注册的“二次攻坚战”
品Spring:注解之王@Configuration和它的一众“小弟们”
品Spring:对@PostConstruct和@PreDestroy注解的处理方法
>>> 热门文章集锦 <<<
爸爸又给Spring MVC生了个弟弟叫Spring WebFlux
【面试】吃透了这些Redis知识点,面试官一定觉得你很NB(干货 | 建议珍藏)
【面试】如果你这样回答“什么是线程安全”,面试官都会对你刮目相看(建议珍藏)
【面试】迄今为止把同步/异步/阻塞/非阻塞/BIO/NIO/AIO讲的这么清楚的好文章(快快珍藏)
【面试】一篇文章帮你彻底搞清楚“I/O多路复用”和“异步I/O”的前世今生(深度好文,建议珍藏)
作者是工作超过10年的码农,现在任架构师。喜欢研究技术,崇尚简单快乐。追求以通俗易懂的语言解说技术,希望所有的读者都能看懂并记住。下面是公众号和知识星球的二维码,欢迎关注!

品Spring:对@Autowired和@Value注解的处理方法的更多相关文章
- Spring @Resource,@Autowired,@Qualifier的注解注入和区别
spring2.5提供了基于注解(Annotation-based)的配置,我们可以通过注解的方式来完成注入依赖.在Java代码中可以使用 @Resource或者@Autowired注解方式来经行注入 ...
- 品Spring:能工巧匠们对注解的“加持”
问题的描述与方案的提出 在Spring从XML转向注解时,为了自身的开发方便,对注解含义进行了扩充(具体参考本号上一篇文章). 这个扩充直接导致了一个问题,就是需要从注解往元注解以及元元注解(即沿着从 ...
- 品Spring:注解之王@Configuration和它的一众“小弟们”
其实对Spring的了解达到一定程度后,你就会发现,无论是使用Spring框架开发的应用,还是Spring框架本身的开发都是围绕着注解构建起来的. 空口无凭,那就说个最普通的例子吧. 在Spring中 ...
- 品Spring:对@PostConstruct和@PreDestroy注解的处理方法
在bean的实例化过程中,也会用到一系列的相关注解. 如@PostConstruct和@PreDestroy用来标记初始化和销毁方法. 平常更多的是侧重于应用,很少会有人去了解它背后发生的事情. 今天 ...
- 品Spring:对@Resource注解的处理方法
@Resource是Java的注解,表示一个资源,它具有双向的含义,一个是从外部获取一个资源,一个是向外部提供一个资源. 这其实就对应于Spring的注入和注册.当它用在字段和方法上时,表示前者.当它 ...
- 品Spring:真没想到,三十步才能完成一个bean实例的创建
在容器启动快完成时,会把所有的单例bean进行实例化,也可以叫做预先实例化. 这样做的好处之一是,可以及早地发现问题,及早的抛出异常,及早地解决掉. 本文就来看下整个的实例化过程.其实还是比较繁琐的. ...
- 品Spring:关于@Scheduled定时任务的思考与探索,结果尴尬了
非Spring风格的代码与Spring的结合 现在的开发都是基于Spring的,所有的依赖都有Spring管理,这没有问题. 但是要突然写一些非Spring风格的代码时,可能会很不习惯,如果还要和Sp ...
- 品Spring:SpringBoot和Spring到底有没有本质的不同?
现在的Spring相关开发都是基于SpringBoot的. 最后在打包时可以把所有依赖的jar包都打进去,构成一个独立的可执行的jar包.如下图13: 使用java -jar命令就可以运行这个独立的j ...
- 品Spring:负责bean定义注册的两个“排头兵”
别看Spring现在玩的这么花,其实它的“筹码”就两个,“容器”和“bean定义”. 只有先把bean定义注册到容器里,后续的一切可能才有可能成为可能. 所以在进阶的路上如果要想走的顺畅些,彻底搞清楚 ...
随机推荐
- jdk13快来了,jdk8的这几点应该看看!
说明 jdk8虽然出现很久了,但是可能我们还是有很多人并不太熟悉,本文主要就是介绍说明一些jdk8相关的内容. 主要会讲解: lambda表达式 方法引用 默认方法 Stream 用Optional取 ...
- cogs2823求组合数(lucas定理
http://cogs.pro:8080/cogs/problem/problem.php?pid=vNQJJVUVj 再写个数学水题,其实lucas适用于m,n比较大而p比较小的情况. 题意:给出两 ...
- 牛客小白月赛6 A 鲲 数学
链接:https://www.nowcoder.com/acm/contest/136/A来源:牛客网 北冥有鱼,其名为鲲,鲲之大,不知其几千里也. ——<庄子·逍遥游> HtBest有一 ...
- POJ 2488 A Knight's Journey (DFS)
poj-2488 题意:一个人要走遍一个不大于8*8的国际棋盘,他只能走日字,要输出一条字典序最小的路径 题解: (1)题目上说的"The knight can start and end ...
- [译]Introduction to Concurrency in Spring Boot
当我们使用springboot构建服务的时候需要处理并发.一种错误的观念认为由于使用了Servlets,它对于每个请求都分配一个线程来处理,所以就没有必要考虑并发.在这篇文章中,我将提供一些建议,用于 ...
- 【Offer】[55-2] 【平衡二叉树】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 输入一棵二叉树的根节点,判断该树是不是平衡二叉树.如果某二叉树中任意节点的左.右子树的深度相差不超过1,那么它就是一棵平衡二叉树.例如, ...
- 【LeetCode】[0002] 【两数之和】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 给出两个非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字.如果 ...
- Java面试-动态规划与组合数
最近在刷力扣上的题目,刷到了65不同路径,当初上大学的时候,曾在hihocoder上刷到过这道题目,但是现在已经几乎全忘光了,大概的知识点是动态规划,如今就让我们一起来回顾一下. 从题目说起 题目原文 ...
- CVE-2014-6271 Shellshock 破壳漏洞 复现
补坑. 什么是shellshock ShellShock是一个BashShell漏洞(据说不仅仅是Bash,其他shell也可能有这个漏洞). 一般情况来说,系统里面的Shell是有严格的权限控制的, ...
- 实验吧CTF练习题---WEB---因缺思汀的绕过解析
实验吧web之因缺思汀的绕过 地址:http://www.shiyanbar.com/ctf/1940 flag值: 解题步骤: 1.点开题目,观察题意 2.通过观察题目要求,判断此道题还有代码审 ...