在程序中使用构造方法的方式
- 如果程序员不做任何处理,则默认用无参构造,或者只有一个构造方式,那就用那个。
- 如果程序员指定了构造方法参数,比如通过getbean()或者BeanDefinition.getConstructorArgumentValues()指定,那就根据入参匹配构造方法,默认匹配不到就报错。
- 在spring的xml中使用autowide="constructor"。则会让spring自动寻找构造方法。
- 在程序中使用@autowide注解在某个构造方法上,则优先使用这个构造方法,构造方法的参数由spring自动寻找。
构造方法推断流程
- 如果程序员指定了构造方法入参值,通过getbean()或者BeanDefinition.getConstructorArgumentValues()指定,那就优先根据入参匹配构造方法,默认情况下如果找不到那就报错,也可修改beanDefinition的ResolvedAutowireMode值为AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR,此时spring会选择参数个数大于传入参数个数最多的构造方法。程序员指定构造方法参数只对非懒加载的单例bean生效。
- 默认情况下,即程序员没有指定构造方法参数,程序中也没有加@Autowide或@Lookup注解,如果只有一个构造方法,那就用那个,构造方法的参数由spring自动寻找注入(先ByType后ByName)或在xml中程序员指定。如果有多个构造方法,则只能用无参构造方法,没有无参构造方法则报错。
- 如果程序员通过@Autowide注解指定了某个构造方法,这时由spring自动去寻找该构造方法的入参值。原则是,如果只有一个构造方法上加了@Autowide(require=true)那就用这个,如果有一个构造方法上加了@Autowide(require=true)的同时,还有其他构造方法加了@Autowide,无论其require等于true还是false,都会报错。如果有多个构造方法上加了@Autowide(require=false),则不管存不存无参构造方法,默认使用参数最多的构造方法。如果参数最多的构造方法存在多个,则根据得分匹配,所谓的得分匹配是根据构造方法的参数类型匹配度匹配得分。这里有两种模式,默认为宽松模式。在宽松模式下不仅仅看找到的bean是否需要类型转换,还看bean的父子级关系,越需要类型转换、父子级差的越远,则得分越高,说明匹配度越低。而在严格模式下,只看是否需要类型转换,越需要类型转换,则得分越高,说明匹配度越低,在严格模式下得分相同就会抛异常。
源码:
1. 构造方法缓存的使用判断
如果获取bean的时候没有指定构造方法的入参,就会使用缓存,否则不会用缓存。具体做法为先看缓存里有没有构造方法及构造方法对应的注入对象,如果有就用缓存的。没有就进行下一步的推断。
2. 构造方法删选
这一步主要是检查构造方法是否有@Lockup/@Autowide注解,如果有,优先根据这些注解推断出构造方法。
具体规则为:
3. 构造方法推断
1. 先检查是否指定了具体的构造方法和构造方法参数值,或者在BeanDefinition中缓存了具体的构造方法或构造方法参数值,如果存在那么则直接使用该构造方法进行实例化
2. 如果没有确定的构造方法或构造方法参数值,那么
i. 如果没有确定的构造方法,那么则找出类中所有的构造方法
ii. 如果只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化
iii. 如果有多个可用的构造方法或者当前Bean需要自动通过构造方法注入
iv. 根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数
v. 对所有的构造方法进行排序,参数个数多的在前面
vi. 遍历每个构造方法
vii. 如果不是调用getBean方法时所指定的构造方法参数值,那么则根据构造方法参数类型找值
viii. 如果时调用getBean方法时所指定的构造方法参数值,就直接利用这些值 ix. 如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的