我们来谈一谈Spring中的属性注入

目录

前言
源码分析
  doCreateBean
  applyMergedBeanDefinitionPostProcessors
  populateBean
总结

本系列文章:

读源码,我们可以从第一行读起

你知道Spring是怎么解析配置类的吗?

配置类为什么要添加@Configuration注解?

谈谈Spring中的对象跟Bean,你知道Spring怎么创建对象的吗?

推荐阅读:

Spring官网阅读 | 总结篇

Spring杂谈

本系列文章将会带你一行行的将Spring的源码吃透,推荐阅读的文章是阅读源码的基础!

前言

在前面的文章中已经知道了Spring是如何将一个对象创建出来的,那么紧接着,Spring就需要将这个对象变成一个真正的Bean了,这个过程主要分为两步

  1. 属性注入
  2. 初始化

在这两个过程中,Bean的后置处理器会穿插执行,其中有些后置处理器是为了帮助完成属性注入或者初始化的,而有些后置处理器是Spring提供给程序员进行扩展的,当然,这二者并不冲突。整个Spring创建对象并将对象变成Bean的过程就是我们经常提到了Spring中Bean的生命周期。当然,本系列源码分析的文章不会再对生命周期的概念做过多阐述了,如果大家有这方面的需求的话可以参考我之前的文章,或者关注我的公众号:程序员DMZ

Spring官网阅读(九)Spring中Bean的生命周期(上)

Spring官网阅读(十)Spring中Bean的生命周期(下)

源码分析

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean,闲话不再多说,我们正式进入源码分析阶段,本文重点要分析的方法就是其源码如下:

doCreateBean

 

 

applyMergedBeanDefinitionPostProcessors

源码如下:

这个时候我们就要思考一个问题,容器中现在有哪些后置处理器是MergedBeanDefinitionPostProcessor呢?

查看这个方法的实现类我们会发现总共就这么几个类实现了MergedBeanDefinitionPostProcessor接口。实际上除了ApplicationListenerDetector之外,其余的后置处理器的逻辑都差不多。我们在这里我们主要就分析两个后置处理

  1. ApplicationListenerDetector
  2. AutowiredAnnotationBeanPostProcessor

ApplicationListenerDetector

首先,我们来ApplicationListenerDetector,这个类在之前的文章中也多次提到过了,它的作用是用来处理嵌套Bean的情况,主要是保证能将嵌套在Bean标签中的ApplicationListener也能添加到容器的监听器集合中去。我们先通过一个例子来感受下这个后置处理器的作用吧

配置文件:

示例代码:

说明OrderService已经被添加到了容器的监听器集合中。但是请注意,在这种情况下,如果要使OrderService能够执行监听的逻辑,必须要满足下面这两个条件

  • 外部的Bean要是单例的,对于我们的例子而言就是dmzService
  • 内嵌的Bean也必须是单例的,在上面的例子中也就是orderService必须是单例

另外需要注意的是,这种嵌套的Bean比较特殊,它虽然由Spring创建,但是确不存在于容器中,就是说我们不能将其作为依赖注入到别的Bean中。

AutowiredAnnotationBeanPostProcessor

对应源码如下:

上面代码的核心逻辑就是

  • 找到所有的注入点,其实就是被@Autowired注解修饰的方法以及字段,同时静态的方法以及字段也会被排除
  • 排除掉被外部管理的注入点,在后续的源码分析中我们再细说

findAutowiringMetadata

buildAutowiringMetadata

难点代码分析

上面的代码整体来说应该很简单,就如我们之前所说的,处理带有@Autowired注解的字段及方法,同时会过滤掉所有的静态字段及方法。上面复杂的地方在于对桥接方法的处理,可能大部分人都没办法理解这几行代码:

要理解这些代码,首先你得知道什么是桥接,为此我已经写好了一篇文章:

Spring杂谈 | 从桥接方法到JVM方法调用

除了在上面的文章中提到的桥接方法外,还有一种特殊的情况

在理解了什么是桥接之后,那么上边的第一行代码你应该就能看懂了,就以上面的代码为例,B中会生成一个桥接方法,对应的被桥接的方法就是A中的test方法。

接着,我们看看第二行代码

最后,再来看看第三行代码,核心就是这句method.equals(ClassUtils.getMostSpecificMethod(method, clazz)。这句代码的主要目的就是为了处理下面这种情况

这种情况下,在处理D中的@Autowired注解时,虽然我们要处理父类中的@Autowired注解,但是因为子类中的方法已经复写了父类中的方法,所以此时应该要跳过父类中的这个被复写的方法,这就是第三行代码的作用。

小结

到这里我们主要分析了applyMergedBeanDefinitionPostProcessors这段代码的作用,它的执行时机是在创建对象之后,属性注入之前。按照官方的定义来说,到这里我们仍然可以使用这个方法来修改bd的定义,那么相对于通过BeanFactoryPostProcessor的方式修改bd,applyMergedBeanDefinitionPostProcessors这个方法影响的范围更小,BeanFactoryPostProcessor影响的是整个Bean的生命周期,而applyMergedBeanDefinitionPostProcessors只会影响属性注入之后的生命周期。

其次,我们分析了Spring中内置的MergedBeanDefinitionPostProcessor,选取了其中两个特殊的后置处理器进行分析,其中ApplicationListenerDetector主要处理内嵌的事件监听器,而AutowiredAnnotationBeanPostProcessor主要用于处理@Autowired注解,实际上我们会发现,到这里还只是完成了@Autowired注解的解析,还没有真正开始进行注入,真正注入的逻辑在后面我们要分析的populateBean方法中,在这个方法中会使用解析好的注入元信息完成真正的属性注入,那么接下来我们就开始分析populateBean这个方法的源码。

populateBean

循环依赖的代码我们暂且跳过,后续出一篇专门文章解读循环依赖,我们直接看看populateBean到底做了什么。

上面这段代码主要可以拆分为三个部分

  1. 处理自动注入
  2. 处理属性注入(主要指处理@Autowired注解),最重要
  3. 处理依赖检查

处理自动注入

autowireByName

对应源码如下:

看到了吗?代码就是这么的简单,不是要通过名称注入吗?直接通过beanName调用getBean,完事儿

autowireByType

resolveDependency

这个方法在Spring杂谈 | 什么是ObjectFactory?什么是ObjectProvider?已经做过分析了,本文不再赘述。

可以看到,真正做事的方法是doResolveDependency

doResolveDependency

findAutowireCandidates

处理属性注入(@Autowired)

postProcessProperties

字段的属性注入

方法的属性注入

处理依赖检查

将解析出来的属性应用到Bean上

到这一步解析出来的属性主要有三个来源

  1. XML中配置的
  2. 通过byName的方式自动注入的
  3. 通过byType的方式自动注入的

但是在应用到Bean前还需要做一步类型转换,这一部分代码实际上跟我们之前在Spring官网阅读(十四)Spring中的BeanWrapper及类型转换介绍的差不多,而且因为XML跟自动注入的方式都不常见,正常@Autowired的方式进行注入的话,这个方法没有什么用,所以本文就不再赘述。

总结

本文我们主要分析了Spring在属性注入过程中的相关代码,整个属性注入可以分为两个部分

  1. @Autowired/@Vale的方式完成属性注入
  2. 自动注入(byType/byName

完成属性注入的核心方法其实就是doResolveDependencydoResolveDependency这个方法的逻辑简单来说分为两步:

  1. 通过依赖类型查询到所有的类型匹配的bean的名称
  2. 如果找到了多个的话,再根据依赖的名称匹配对应的Bean的名称
  3. 调用getBean得到这个需要被注入的Bean
  4. 最后反射调用字段的set方法完成属性注入

从上面也可以知道,其实整个属性注入的逻辑是很简单的。

如果本文对你有帮助的话,记得点个赞吧!

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值