内容简介:假如一个接口(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。。。
如何解决这类问题
- 如果有两个实现类,还要使用@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的原理。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 详细分析@Autowired注解与@resource注解的区别
- Spring Boot注解分析
- Spring Boot源码分析 - Configuration注解
- SpringBoot 启动分析(四) — 注解驱动的 Bean 定义加载
- SpringBoot2 | @SpringBootApplication注解 自动化配置流程源码分析(三)
- Spring 注解编程之模式注解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据化运营速成手册
胡晨川 / 电子工业出版社 / 2017-4 / 55
《数据化运营速成手册》用于提升互联网公司员工的数据应用能力,即数据化运营能力。首先,从最常用的数据图表切入,帮助执行层正确地绘图,管理层正确地看图;接着,梳理运营中最基本的数据应用知识,涉及数据获取、数据清洗、数据认知、分析框架、指标体系、运营实验等内容。然后,介绍作者认为必要的统计学知识,包括假设检验、方差分析、回归分析和时间序列分解,并引入了管理科学中的规划求解方法。最后,介绍了数据分析工具的......一起来看看 《数据化运营速成手册》 这本书的介绍吧!