文章目录
- 源码思路
- autowireConstructor()
Spring中的一个bean,需要实例化得到一个对象,而实例化就需要用到构造方法。
一般情况下,一个类只有一个构造方法:
- 要么是无参的构造方法
- 要么是有参的构造方法
如果只有一个无参的构造方法,那么实例化就只能使用这个构造方法了。 如果只有一个有参的构造方
法,那么实例化时能使用这个构造方法吗?要分情况讨论: - 使用AnnotationConfigApplicationContext,会使用这个构造方法进行实例化,那么Spring会
根据构造方法的参数信息去寻找bean,然后传给构造方法 - 使用ClassPathXmlApplicationContext,表示使用XML的方式来使用bean,要么在XML中指定
构造方法的参数值(手动指定),要么配置autowire=constructor让Spring自动去寻找bean做为
构造方法参数值。
上面是只有一个构造方法的情况,那么如果有多个构造方法呢?
又分为两种情况,多个构造方法中存不存在无参的构造方法。
分析:一个类存在多个构造方法,那么Spring进行实例化之前,该如何去确定到底用哪个构造方法
呢? - 如果开发者指定了想要使用的构造方法,那么就用这个构造方法
- 如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动去选择构造方法
- 如果开发者也没有让Spring自动去选择构造方法,则Spring利用无参构造方法,如果没有无参构
造方法,则报错
针对第一点,开发者可以通过什么方式来指定使用哪个构造方法呢? - xml中的标签,这个标签表示构造方法参数,所以可以根据这个确定想要使
用的构造方法的参数个数,从而确定想要使用的构造方法 - 通过@Autowired注解,@Autowired注解可以写在构造方法上,所以哪个构造方法上写了
@Autowired注解,表示开发者想使用哪个构造方法,当然,它和第一个方式的不同点是,通过
xml的方式,我们直接指定了构造方法的参数值,而通过@Autowired注解的方式,需要Spring
通过byType+byName的方式去找到符合条件的bean作为构造方法的参数值
再来看第二点,如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动去选择构
造方法,对于这一点,只能用在ClassPathXmlApplicationContext,因为通过
AnnotationConfigApplicationContext没有办法去指定某个bean可以自动去选择构造方法,而通过
ClassPathXmlApplicationContext可以在xml中指定某个bean的autowire为constructor,虽然这个
属性表示通过构造方法自动注入,所以需要自动的去选择一个构造方法进行自动注入,因为是构造方
法,所以顺便是进行实例化。
当然,还有一种情况,就是多个构造方法上写了@Autowired注解,那么此时Spring会报错。 但
是,因为@Autowired还有一个属性required,默认为ture,所以一个类中,只有能一个构造方法标
注了@Autowired或@Autowired(
required=true),有多个会报错。但是可以有多个
@Autowired(
required=false),这种情况下,需要Spring从这些构造方法中去自动选择一个构造
方法。
源码思路
- AbstractAutowireCapableBeanFactory类中的createBeanInstance()方法会去创建一个Bean
实例 - 根据BeanDefinition加载类得到Class对象
- 如果BeanDefinition绑定了一个Supplier,那就调用Supplier的get方法得到一个对象并直接返
回 - 如果BeanDefinition中存在factoryMethodName,那么就调用该工厂方法得到一个bean对象
并返回 - 如果BeanDefinition已经自动构造过了,那就调用autowireConstructor()自动构造一个对象
- 调用SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors()方
法得到哪些构造方法是可以用的 - 如果存在可用得构造方法,或者当前BeanDefinition的autowired是
AUTOWIRE_CONSTRUCTOR,或者BeanDefinition中指定了构造方法参数值,或者创建Bean
的时候指定了构造方法参数值,那么就调用**autowireConstructor()**方法自动构造一个对象 - 最后,如果不是上述情况,就根据无参的构造方法实例化一个对象
autowireConstructor()
- 先检查是否指定了具体的构造方法和构造方法参数值,或者在BeanDefinition中缓存了具体的构
造方法或构造方法参数值,如果存在那么则直接使用该构造方法进行实例化 - 如果没有确定的构造方法或构造方法参数值,那么
i. 如果没有确定的构造方法,那么则找出类中所有的构造方法
ii. 如果只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化
iii. 如果有多个可用的构造方法或者当前Bean需要自动通过构造方法注入
iv. 根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数
v. 对所有的构造方法进行排序,参数个数多的在前面
vi. 遍历每个构造方法
vii. 如果不是调用getBean方法时所指定的构造方法参数值,那么则根据构造方法参数类型找值
viii. 如果时调用getBean方法时所指定的构造方法参数值,就直接利用这些值
ix. 如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是
不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,
这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的