代码入口:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor
org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor()
当 BeanDefinition 没有指定 Supplier,也没有指定工厂方法时,需要推断使用哪个构造方法进行 Bean 的初始化
Spring 的判断逻辑如下:
- 类中所有构造方法上都没有
@Autowired
注解- 只有一个无参构造方法,选用此构造方法
- 只有一个有参的构造方法,选用此构造方法,通过 依赖注入#依赖查找 找到对应的入参 Bean
- 有一个无参构造方法,和一或多个有参构造方法,使用无参构造方法
- 只有多个有参构造方法,抛异常
- 类中存在
@Autowired
注解的构造方法(@Autowired
的required
属性默认为 true)- 只有一个
@Autowired
的required
为 true 的构造方法,选用此构造方法,通过 依赖注入#依赖查找 找到对应的入参 Bean - 有多个
@Autowired
标注的构造方法,其中一或多个构造方法的required
属性默认为 true,抛异常 - 所有被
@Autowired
标注的构造方法的required
属性都为 false,继续判断
- 只有一个
构造方法匹配度计分
计分方式分为 宽松模式(默认) 和 严格模式,可以在 BeanDefinition 设置(AbstractBeanDefinition.lenientConstructorResolution
默认为 true)
宽松模式
宽松模式会更细粒度的计分
对于查找到的依赖的 Bean,
- 如果 Bean 类型与参数类型完全相同,计 0 分
- 如果 Bean 实现(
implements
)了参数类型,计 1 分,每多一层implements
加 1 分 - 如果 Bean 继承(
extends
)了参数类型,计 2 分,每多一层extends
加 2 分
例如:
@Component
class A extends B implements D {}
class B extends C {}
@Component
class Foo {
Foo(A a) {}
Foo(D d) {}
Foo(B b) {}
Foo(C c) {}
}
由于 Spring 进行依赖查找只能找到 A 作为构造方法的参数 bean
构造方法 Foo(A a) {}
计 0 分,因为参数类型 A 和找到的 bean 类型完全相同,计 0 分
构造方法 Foo(D d) {}
计 1 分,因为参数类型 D 是 A 的上级接口,计 1 分
构造方法 Foo(B b) {}
计 2 分,因为参数类型 B 是 A 的上级类,计 2 分
构造方法 Foo(C c) {}
计 4 分,因为参数类型 C 是 B 的上级类,B 是 A 的上级类,计 2 + 2 = 4 分
严格模式
对于查找到的依赖的 Bean,如果 Bean 的类型与构造方法得参数类型相同,得分较小,如果类型不相同,则得分较大
@Bean 方法重载
Spring 会把 @Bean
修饰的方法解析成 BeanDefinition:
例如:
@Configuration
public class AppConfig {
@Bean
public static AService aService(){
return new AService();
}
@Bean
public AService aService(BService bService){
return new AService();
}
}
- 如果方法不是 static 的,那么解析出来的 BeanDefinition 中:
- factoryBeanName 为 AppConfig 所对应的 beanName,比如”appConfig”
- factoryMethodName 为对应的方法名,比如 “aService”
- factoryClass为AppConfig.class
- 如果方法是 static 的,那么解析出来的 BeanDefinition 中:
- factoryBeanName为null
- factoryMethodName 为对应的方法名,比如 “aService”
- factoryClass也为AppConfig.class
在由@Bean
生成的 BeanDefinition 中,有一个重要的属性 isFactoryMethodUnique
,用来表示 factoryMethod 是不是唯一。
当 @Bean
标注的方法不存在方法重载,则生成的 BeanDefinition 的 isFactoryMethodUnique
属性为 true,表示当前 Bean 的 factoryMethod 唯一。
当 @Bean
标注的方法出现了方法重载,比如两个 @Bean
的方法名相同,但参数不同,Spring 扫描到第一个 @Bean
方法时,会生成一个 aService 的 BeanDefinition,此时 isFactoryMethodUnique
为 true,当解析到第二个同名 @Bean
方法时,会判断出来 beanDefinitionMap 中已经存在一个 aService
的 BeanDefinition 了,则不会再创建一个 BeanDefinition,而会将之前的 BeanDefinition 的 isFactoryMethodUnique
修改为 false,表示该 Bean 的 factoryMethod 不唯一。
后续在根据 BeanDefinition 创建 Bean 时,会根据 isFactoryMethodUnique
判断
- 如果为 true,表示当前 BeanDefinition 只对应了一个 factoryMethod 方法,直接用这个方法来创建 Bean
- 如果为 false,表示当前 BeanDefinition 对应了多个 factoryMethod 方法,需要执行推断构造方法的逻辑,判断选择使用哪个方法来创建 Bean。