@Autowired使用过程中遇到疑问,通过源码解析原因
- 一、起因
- 1、当person只有一个实现类时,TestController中,Person属性随意取名。
- 2、当有Person两个实现类时,TestController中,属性名称必须和实现类名一致(man或woman),否则会报错。
- 二、@Auowired调用过程
- # 1、目标类属性信息获取流程
- # 2、属性赋值流程
- 三、@Auowired解决问题的源码逻辑
一、起因
当前person接口有两个实现类,man和woman。一个测试接口TestController。
1、当person只有一个实现类时,TestController中,Person属性随意取名。
2、当有Person两个实现类时,TestController中,属性名称必须和实现类名一致(man或woman),否则会报错。
二、@Auowired调用过程
# 1、目标类属性信息获取流程
doCreateBean->applyMergedBeanDefinitionPostProcessors遍历执行postProcessMergedBeanDefinition方法,其中AutowiredAnnotationBeanPostProcessor类符合条件,执行findAutowiringMetadata方法,然后buildAutowiringMetadata中使用反射获取目标类带有@Autowired的属性信息,封装成AutowiredFieldElement(继承InjectionMetadata)对象,最后把目标类名为key,属性信息为value存入injectionMetadataCache集合中。
# 2、属性赋值流程
doCreateBean->populateBean中循环执行InstantiationAwareBeanPostProcessor类型的后置处理器,调用postProcessPropertyValues方法。AutowiredAnnotationBeanPostProcessor满足条件,执行postProcessPropertyValues->findResourceMetadata,此方法获取目标类属性信息,通过injectionMetadataCache集合,返回InjectionMetadata类后,执行InjectionMetadata中inject方法,循环InjectedElement类型的目标类属性集合,执行InjectedElement中inject方法,根据属性信息,从springIoc容器中获取目标属性,最后使用反射给目标类赋值。
三、@Auowired解决问题的源码逻辑
根据二步骤中AutowiredFieldElement.inject方法,继续DefaultListableBeanFactory中resolveDependency方法,调用doResolveDependency方法,继续执行findAutowireCandidates。
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());
获取到了实现了所有person类的对象名称。**从参数requiredType可以看出@Autowried是通过属性类型给属性赋值的。**最终返回Map<String, Object> 集合,key为目标属性名称,value为目标属性实体,如果属性有多个实现类,此集合中就会有多个key,value。
从下面图片可以看出,判断matchingBeans目标属性是多个还是一个。多个会使用属性名称为key获取属性实体,一个会默认获取,这就解释了多实现时,需要使用正确的属性名称,单个实现时,属性名称可以随意。