上篇博客说了自动注入模型的使用,这篇笔记打算记录下自动注入模型中,autowireMode为0的情况,也就是我们经常用到的@Autowired、@Resource注解的原理
首先对于这两个注解,都是由后置处理器来完成解析的,解析的时机是一样的,在第六个后置处理器执行的时候;但是是由不同的后置处理器来完成解析的
@Autowired注解:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues
@Resource注解:
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessPropertyValues
前言
1、这两个注解,都是在第六个后置处理器执行的时候,进行解析的,但是在第三个处理器
org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
执行的时候,会先解析一下当前bean中有哪些属性要进行注入,在第六个后置处理器执行的时候,就无须进行解析,直接从map中获取要注入的属性即可
2、这两个注解虽然是由不同的后置处理器处理的,但是处理的思想、步骤大致都是一样的:
- 会先尝试获取bean中添加了该注解的方法(method)和属性(field)
- 找到之后,会根据实现类的优先级、或者是name等从容器中或者beanDefinitionMap中找到对应的属性
- 通过filed.set()完成属性的注入
3、这里有几个点要先行说明:
- 对于@Resource注解,会根据要注入属性的name,从单实例池中获取bean,完成属性注入
- 对于@Autowired注解,我们通常说是现根据类型注入,如果找到多个或者没有找到,再根据name进行注入;这里要说明的是:spring在解析@Autowired注解的时候,并不是直接从单实例池中查找bean,而是先从beanDefinitionMap中,根据type查找,如果找到多个,再根据name从单实例池中查找,只有找到确定要注入哪个类,才会从单实例池中找到对应的bean,完成注入
- 当然,和@Autowired注解配合使用的注解有好几个,在下面会一一解析
@Autowired
这是@Autowired注解解析的整个流程,其中,和@Autowired注解配合使用的有几下几个注解:
@Qualifier
@Primary
@Priority
第一个注解使用在field上,在根据类型从beanDefinitionMap中找到bean之后,会判断哪个beanName是否是合格的;如果要注入的bean有多个实现类,会优先注入@Qualifier注解指定的实现类
第二个直接是在类上使用的,在未添加@Qualifier注解的场景下,如果有多个实现类,会判断哪个实现类上添加了@Primary注解,添加了,就注入该实现类
第三个注解也是加载类上,如果既没有添加@Qualifer、也没有添加@Priority注解,那么,会判断哪个实现类的优先级比较高,值越小,优先级越高
这是
org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency
的部分代码
/**
* @Autowired注解源码 三
* 查找要注入的bean,按照type来查找,如果匹配到一个,就获取到这个实例,然后返回,返回之后,会调用field.set();注入进去
* 如果找到了多个,那就先判断哪个实现类有@primary注解,如果都没有注解,那就判断priority的优先级
*
* 这个方法中,对Qualifier注解进行了处理;如果一个接口有多个实现类,但是没有加@Qualifier注解,那么就会返回多个
*
* 如果@Qualifier指定的value在spring容器中没有,这里返回的map集合就是空
*
*/
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
// 如果匹配到的要注入的bean是null,就报错
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}