本节主要讲解spring怎么去实例化对象的,也就是推断构造方法。
一、实例化对象的方式
首先我们需要知道spring容器来实例化一个对象时,它内部有如下四种方式来进行实例化一个对象:
默认情况
1、如果对象只有一个构造方法,则直接使用这个构造方法。
2、如果有多个构造方法,则直接使用无参构造方法,如果没有无参构造方法,实例化会直接报错。
使用注解方式
如果使用了@Autowired注解:
-
如果有多个加了@Autowired的构造方法,必须都为false,否则直接报错。然后spring自行选择构造方法以及构造方法的参数值
-
只能有一个@Autowired,并且为true的构造方法,spring自行选择构造方法的的入参值。
构造注入方式
1、如果使用了构造注入 autowire=“constructor”,spring则自动的选择构造方法以及入参值。
这种一般是通过xml方式进行配置bean,如下:
当然也可以通过Beandefinition进行配置,如下:
2、如果使用了构造注入 autowire=“constructor”,并且指定了实例化的参数。
那么spring首先选择构造方法,并把给定的参数值尽量与构造方法需要的参数匹配上(当然这里spring会进行参数类型转换,如果转换失败,将会报错),如果不能匹配,则从spring容器中进行获取。
指定构造方法参数
spring会自行选择构造方法,并尽可能的把给定的参数与构造方法需要的参数进行匹配上(当然这里spring会进行参数类型转换,如果转换失败,将会报错),代码如下所示:
二、源码分析
接下来我们将会通过源码来进行分析,spring推断构造方法的整个过程。为了方便大家看懂源码,源码中有很多细枝末节东西,我都会直接忽略掉。
1、主要逻辑
首先直接来到spring创建对象的方法入口
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
这个方法主要做了三件事:
-
1、获取加了@Autowired相关的逻辑的构造方法
-
2、通过上面获取到的构造方法列表推断构造方法,以及使用构造参数进行实例化
-
3、如果没有找到构造方法,则直接使用无参构造方法进行实例化
2、通过@Autowired获取相关构造方法
主要处理逻辑则是determineConstructorsFromBeanPostProcessors()方法,这里其实是spring通过bean的后置处理器进行处理,具体的调用逻辑在
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors
有兴趣的同学可以研究下AutowiredAnnotationBeanPostProcessor中的处理逻辑,大致的推断构造方法不同情况如下:
3、推断构造方法并实例化
推断构造方法的主要处理逻辑在
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor
最终调用到
org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor
此方法主要做了以下3件事:
-
1、判断是否传入构造参数,以及是否在Beandefinition中设置了构造参数,并计算出构造参数最小个数
-
2、依次遍历构造方法,根据最小构造参数判断,找到大于等于最小参数个数的构造方法,并构造出构造方法需要的构造参数
-
3、计算出最适合的构造方法,并完成实例化
具体源码如下:
第一步:计算出最小参数个数
第二步:依次遍历构造方法
第三步:计算评分
实例化: