Spring源码-Autowired注解
古人说“绝知此事要躬行”,对于学习框架源码更是如此(本篇介绍源码阅读基础)
一 新建干净的项目
一个较多业务逻辑的项目对于源码阅读初入门的人,或多或少有一些干扰。
从模板新建maven项目
添加maven依赖
1 | <dependency> |
准备Bean
1 | // 新建类B |
启动Main方法
1 | public class App |
二 Spring初始化流程认知
refresh流程
大致是如下流程:
- 注解类或xml配置文件读取为BeanDefinition
- 创建BeanFactory
- 通过BeanDefinition为Bean工厂添加各种后置处理
- 遍历BeanDefinition中定义的BeanName,创建->初始化(填充属性、bean前置、自定义初始化、bean后置)
曾经看过马士兵的一次讲课,觉得很清晰,这里借用一下原图:
Bean的生命周期
参考BeanFactory接口注释
Bean工厂的默认实现
Spring对ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的默认实现:基于bean定义元数据的成熟bean工厂,可通过后处理器扩展。
条件断点
这里面设置条件断点:
DefaultListableBeanFactory.doCreateBean
- createBeanInstance(beanName, mbd, args) // 创建Bean
- populateBean(beanName, mbd, instanceWrapper) // 填充Bean属性
- ibp.postProcessProperties // 这一行,注意ibp实现类为AutowiredAnnotationBeanPostProcessor
- metadata.inject(bean, beanName, pvs);
内部调用顺序:
InjectionMetadata. inject -> AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement.inject
三 源码Trace
在实例化和初始化位置打条件断点
在Bean的填充属性位置打条件断点,注意此处处理BP类型
获取到需要注入的元数据后,执行注入
然后是调用属性类的注入方法
注意这里是继承内部类后复写的方法 ,OMG
1 | private class AutowiredFieldElement extends InjectionMetadata.InjectedElement |
解决依赖 resolveDependency
获取实例化对象b后,反射调用set注入
递归调用b的属性填充
对于没有下级依赖的属性,在填属性(populateBean)的时候依旧会走到inject方法,但是它的对象是InjectionMetadata.EMPTY ,会直接返回
四 总结
Autowired的逻辑主要是在填充属性(populateBean)的时候,doResolveDependency进行处理的。
- 首先会通过findAutowireCandidates查找所有类型匹配的类, 如果找不到直接异常
- 如果有多个候选,那么determineAutowireCandidate会进行决定最终的候选,逻辑:
- 是否有@Primary来赋予bean更高的优先级
- 看是否实现了OrderComparator,通过更高优先级来匹配
- 通过给定的名称匹配
在熟悉既有逻辑后,不妨思考一下以前学习Autowired自动装配的规则(优先类型匹配,然后名称匹配):
可以将类型变更为接口,或者Object,又或者改下默认的field名称,看是否可以匹配上。对应的源码又是怎么走的。