Spring源码分析:@Autowired注解原理分析

36次阅读

共计 3373 个字符,预计需要花费 9 分钟才能阅读完成。

前言
关于 @Autowired 这个注解,我们再熟悉不过了,经常跟 @Resource 来做对比,这篇文章我们不讨论两者有何异同,仅分析 @Autowired 的原理(基于 Spring5)。
问题
假如一个接口 (IUserService) 有两个实现类,分别是 (UserServiceImpl01) 和(UserServiceImpl02),在我们给类注入的时候,这样写 (@Autowired private IUserService userService) 会发生什么情况?答案肯定是报错,那么原理呢?文字描述:因为首先 @Autowired 是按照类型注入的,也就是.class,但 UserServiceImpl01 和 UserServiceImpl02 都是 IUserService 类型的,于是 Spring 就会按照后面的名字 (userService) 在容器中查找,但发现根本没有这个名字,因为两个实现类在不指定名字情况下,就是首字母小写的类名,然后抛出异常:expected single matching bean but found 2。。。
如何解决这类问题

如果有两个实现类,还要使用 @Autowired 注解,可以将 userService 改成我们指定的实现类名称,比如 UserServiceImpl01,或者不想改 userService,可以加 @Qualifier(value = “userServiceImpl01”),指定需要注入的实现类。
使用 @Resource 注解,手动指定实现类名称。

还有很多种方法,但基本思想都一样,无非就是如何区分两个同祖宗的儿子,既然根儿相同,那就只有指定名字了。
@Autowired 原理
提到 @Autowired 我们一般都知道叫依赖注入

什么是依赖注入?
什么是注入,注到哪里?
什么时候注入的?

什么是依赖注入?
依赖注入:Dependency Injection,简称 DI,说白了就是利用反射机制为类的属性赋值的操作。
什么是注入,注入到哪里?
注入就是为某个对象的外部资源赋值,注入某个对象所需要的外部资源(包括对象、资源、常量数据等)。IOC 容器注入应用程序某个对象,应用程序所依赖的对象。
什么时候注入的?
在完成对象的创建,为对象变量进行赋值的时候进行注入(populate)。
源码分析
首先点开 @Autowired,注释上写 Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor,让我们去查阅这个类,看一下这个类的继承关系树,如下:
可见它间接实现 InstantiationAwareBeanPostProcessor,就具备了实例化前后 (而不是初始化前后) 管理对象的能力,实现了 BeanPostProcessor,具有初始化前后管理对象的能力,实现 BeanFactoryAware,具备随时拿到 BeanFactory 的能力,也就是说,这个 AutowiredAnnotationBeanPostProcessor 具备一切后置处理器的能力。

容器在初始化的时候,后置处理器的初始化要优先于剩下自定义 Bean(比如我们自定义的 Service,Controller 等等)的初始化的,我们自定义的 Bean 初始化是在 finishBeanFactoryInitialization(beanFactory)这里完成的,来到 AbstractApplicationContext 的 refresh()方法。
finishBeanFactoryInitialization(beanFactory)–>beanFactory.preInstantiateSingletons()–>getBean(beanName)–>doGetBean(beanName)–> 来到 AbstractBeanFactory 第 317 行 createBean(beanName, mbd, args),来创建 bean 实例 –> 来到 AbstractAutowireCapableBeanFactory 第 503 行 doCreateBean(beanName, mbdToUse, args)–> 紧接着来到 AbstractAutowireCapableBeanFactory 的第 543 行,instanceWrapper = createBeanInstance(beanName, mbd, args)就已经把 Bean 实例创建出来了,只不过 instanceWrapper 是一个被包装过了的 bean,它里面的属性还未赋实际值 –> 然后来到第 555 行 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName),这一步的作用就是将所有的后置处理器拿出来,并且把名字叫 beanName 的类中的变量都封装到 InjectionMetadata 的 injectedElements 集合里面,目的是以后从中获取,挨个创建实例,通过反射注入到相应类中。

紧接着来到 AbstractAutowireCapableBeanFactory 第 588 行 populateBean(beanName, mbd, instanceWrapper)–> 点进去,来到 AbstractAutowireCapableBeanFactory 的第 1347 行,来循环遍历所有的后置处理器 for (BeanPostProcessor bp : getBeanPostProcessors()),从方法名字 postProcessPropertyValues 也能看出来,就是给属性赋值,当 bp 是 AutowiredAnnotationBeanPostProcessor 的时候,进入 postProcessPropertyValues 方法,来到 AutowiredAnnotationBeanPostProcessor 的 postProcessPropertyValues 方法,如下:
首先找到需要注入的哪些元数据,然后 metadata.inject(注入),注入方法点进去,来到 InjectionMetadata 的 inject 方法,在一个 for 循环里面依次执行 element.inject(target, beanName, pvs),来对属性进行注入。
进入 element.inject(target, beanName, pvs),注意,这里必须要 debug 才可以进入真正的方法。来到 AutowiredAnnotationBeanPostProcessor 的 inject 方法,
第 584 行,value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter),由工厂解析这个依赖,进入,来到 DefaultListableBeanFactory 第 1065 行,result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter)再次解析依赖,点击进入,来到 DefaultListableBeanFactory 的 doResolveDependency()方法,前面是一堆判断,比较,查看属性类型,这种类型的有几个(matchingBeans),如果只有一个匹配,那么来到第 1138 行,instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this),进入这个方法,可以看到就是前面说的根据工厂来创建实例的过程了:beanFactory.getBean(beanName),其中这个 beanName 就是属性的名称,当经过一系列操作完成属性的实例化后,便来到 AutowiredAnnotationBeanPostProcessor 的第 611 行,利用反射为此对象赋值。这样,对象的创建以及赋值就完成了。
总结
在容器启动,为对象赋值的时候,遇到 @Autowired 注解,会用后置处理器机制,来创建属性的实例,然后再利用反射机制,将实例化好的属性,赋值给对象上,这就是 Autowired 的原理。

正文完
 0