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

栏目: Java · 发布时间: 6年前

内容简介:假如一个接口(IUserService)有两个实现类,分别是(UserServiceImpl01)和(UserServiceImpl02),在我们给类注入的时候,这样写(@Autowired private IUserService userService)会发生什么情况?答案肯定是报错,那么原理呢?文字描述:因为首先@Autowired是按照类型注入的,也就是.class,但UserServiceImpl01和UserServiceImpl02都是IUserService类型的,于是Spring就会按照后

前言

关于@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,让我们去查阅这个类,看一下这个类的继承关系树,如下:

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

可见它间接实现InstantiationAwareBeanPostProcessor,就具备了实例化前后(而不是初始化前后)管理对象的能力,实现了BeanPostProcessor,具有初始化前后管理对象的能力,实现BeanFactoryAware,具备随时拿到BeanFactory的能力,也就是说,这个AutowiredAnnotationBeanPostProcessor具备一切后置处理器的能力。

  1. 容器在初始化的时候,后置处理器的初始化要优先于剩下自定义Bean(比如我们自定义的Service,Controller等等)的初始化的,我们自定义的Bean初始化是在finishBeanFactoryInitialization(beanFactory)这里完成的,来到AbstractApplicationContext的refresh()方法。
  2. 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集合里面,目的是以后从中获取,挨个创建实例,通过反射注入到相应类中。

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

  1. 紧接着来到AbstractAutowireCapableBeanFactory第588行populateBean(beanName, mbd, instanceWrapper)-->点进去,来到AbstractAutowireCapableBeanFactory的第1347行,来循环遍历所有的后置处理器for (BeanPostProcessor bp : getBeanPostProcessors()),从方法名字postProcessPropertyValues也能看出来,就是给属性赋值,当bp是AutowiredAnnotationBeanPostProcessor的时候,进入postProcessPropertyValues方法,来到AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法,如下:

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

首先找到需要注入的哪些元数据,然后metadata.inject(注入),注入方法点进去,来到InjectionMetadata的inject方法,在一个for循环里面依次执行element.inject(target, beanName, pvs),来对属性进行注入。

  1. 进入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的原理。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Purely Functional Data Structures

Purely Functional Data Structures

Chris Okasaki / Cambridge University Press / 1999-6-13 / USD 49.99

Most books on data structures assume an imperative language such as C or C++. However, data structures for these languages do not always translate well to functional languages such as Standard ML, Ha......一起来看看 《Purely Functional Data Structures》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具