Spring中的一个bean,需要实例化得到对象,而实例化就需要用到构造方法。这篇笔记主要记录Spring Bean生命周期中实例化Bean对象过程中推断构造方法的逻辑
一、回顾一下Spring Bean 的生命周期过程
Spring容器扫描class得到BeanDefinition,从而去生产Bean
1.根据class推断构造方法
2.根据推断出来的构造方法,反射,得到一个对象
3.填充对象中的属性(依赖注入)
4.如果对象中的某个方法被AOP了,那么则需要根据对象生成一个代理对象
5. 把最终生成的代理对象放入单例池(即singletonObjects)中。
二、 Bean中构造方法的业务场景有哪些
- 默认情况,用无参构造器,只有一个构造方法就用这一个
- 多个构造方法,程序中通过getBean()或者BeanDefinition.getConstructorArgumentValues()指定了构造方法参数,就使用与之匹配的构造方法
- 通过@Autowired注解指定了某个构造方法
- 没有如上情况则让Spring自动选择构造方法以及构造方法的入参值:
使用AnnotationConfigApplicationContext,会使用构造方法进行实例化,那么Spring会根据构造方法的参数信息去寻找bean,然后传给构造方法
使用ClassPathXmlApplicationContext,表示使用XML的方式来使用bean,要么在XML中指定构造方法的参数值(手动指定),要么配置autowire=constructor让Spring自动去寻找bean做为构造方法参数值。
三、源码
源码的思维导入:
https://www.processon.com/v/64b0f88ab856374c5c180238
源码主要方法逻辑分析
AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors()
推断出被@Autowired注释的可用的构造方法,方法逻辑如下:
- 获取Bean中的所有构造方法 rawCandidates = beanClass.getDeclaredConstructors();
- 当前遍历的构造方法是否写了@Autowired —findAutowiredAnnotation(candidate);
- .没有Autowired注解的构造方法
- 没有添加了@Autowired注解的构造方法,并且类中只有一个构造方法,并且是有参的.返回这个构造方法。
- 如果有多个有参、并且没有添加@Autowired的构造方法,是会返回null。
- 只有一个无参构造器返回null。
- 有Autowire注解的构造方法
- 有一个Request= true(只有要给构造方法上有Autowire)返回此构造方法
- 有多个Request=ture,抛异常
- 有一个Request= true其余为false, 抛异常
- request 全是false,返回所有构造器和无参构造器
autowireConstructor()
- 先检查是否指定了具体的构造方法和构造方法参数值,或者在BeanDefinition中缓存了具体的构造方法或构造方法参数值,如果存在那么则直接使用该构造方法进行实例化
- 如果没有确定的构造方法或构造方法参数值,那么
- 如果没有确定的构造方法,那么则找出类中所有的构造方法
- 如果只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化
- 如果有多个可用的构造方法或者当前Bean需要自动通过构造方法注入
根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数 - 对所有的构造方法进行排序,参数个数多的在前面
- 遍历每个构造方法
- 如果不是调用getBean方法时所指定的构造方法参数值,那么则根据构造方法参数类型找值
- 如果时调用getBean方法时所指定的构造方法参数值,就直接利用这些值
- 如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的