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

/ Spring源码分析 / 0 条评论 / 369人围观

前言

关于@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。。。

如何解决这类问题

  1. 如果有两个实现类,还要使用@Autowired注解,可以将userService改成我们指定的实现类名称,比如UserServiceImpl01,或者不想改userService,可以加@Qualifier(value = "userServiceImpl01"),指定需要注入的实现类。
  2. 使用@Resource注解,手动指定实现类名称。 还有很多种方法,但基本思想都一样,无非就是如何区分两个同祖宗的儿子,既然根儿相同,那就只有指定名字了。

@Autowired原理

提到@Autowired我们一般都知道叫依赖注入

  1. 什么是依赖注入?
  2. 什么是注入,注到哪里?
  3. 什么时候注入的?

什么是依赖注入?

依赖注入:Dependency Injection,简称DI,说白了就是利用反射机制为类的属性赋值的操作。

什么是注入,注入到哪里?

注入就是为某个对象的外部资源赋值,注入某个对象所需要的外部资源(包括对象、资源、常量数据等)。IOC容器注入应用程序某个对象,应用程序所依赖的对象。

什么时候注入的?

在完成对象的创建,为对象变量进行赋值的时候进行注入(populate)。

源码分析

  1. 首先点开@Autowired,注释上写Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor,让我们去查阅这个类,看一下这个类的继承关系树,如下: 请输入图片描述 可见它间接实现InstantiationAwareBeanPostProcessor,就具备了实例化前后(而不是初始化前后)管理对象的能力,实现了BeanPostProcessor,具有初始化前后管理对象的能力,实现BeanFactoryAware,具备随时拿到BeanFactory的能力,也就是说,这个AutowiredAnnotationBeanPostProcessor具备一切后置处理器的能力。
  2. 容器在初始化的时候,后置处理器的初始化要优先于剩下自定义Bean(比如我们自定义的Service,Controller等等)的初始化的,我们自定义的Bean初始化是在finishBeanFactoryInitialization(beanFactory)这里完成的,来到AbstractApplicationContext的refresh()方法。
  3. 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集合里面,目的是以后从中获取,挨个创建实例,通过反射注入到相应类中。 请输入图片描述
  4. 紧接着来到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),来对属性进行注入。
  5. 进入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的原理。