前言:
大家都熟悉Spring的IOC
和bean实例化
工作过程,那么当一个bean有多个构造器,Spring会在IOC
和bean实例化
过程中选择哪一个最终作为创建bean实例的合格的构造器 呢?这涉及到了Spring的构造器推断的源码部分。
整体框架
关键词:
- 默认构造器
- 注入模型
- 手动装配
- 自动装配
- 合成构造方法
- 标准构造方法
- 合格构造方法
- 默认构造器(defaultConstructor)
- 必须构造器(requiredConstructor)
Spring推断结论:
从不同bean情形下的Spring的构造器推断结果,来进一步根据源码去分析过程
整个装配过程会依据不同的注入模型,注入模型的设置不是全局的,是每个bean可以在DeanDefinition中单独设置的:
- 自动注入:构造方法的自动注入
- AUTOWIRE_NO:默认,即手动装配
其他模式同AUTOWIRE_NO,为AUTOWIRE_NO模式和其他非自动注入模式的分析结果是一致的
手动装配 | 自动装配 | |
---|---|---|
只有一个无参构造器 | 手动装配为null,不会走自动装配,直接反射默认构造器 | 不走 |
只有一个有参构造器 | 手动装配返回该有参构造器(别无它选) | 走,直接创建返回bean |
只有一个@Autowired注解的构造器 | 返回该必须构造器 | 走,必须构造器创建bean |
有多个@Autowired注解,required均为true | 推断报错 | 不走,报错 |
有多个@Autowired注解,只有一个required=true | 推断返回为true的这个构造器 | 走,用推断的构造器创建bean |
有多个@Autowired注解,required均为false | 手动装配返回@Autowired注解的构造器集合 | 走,选择最优的一个构造器创建bean |
有一个无参构造器 + 多个有参构造器 | 手动装配结果为null,最终反射默认构造器 | 不走 |
多个有参构造器 | 手动装配结果为null,默认模式最终抛异常”未发现默认构造器“ | 若默认注入模式,不走;若自动装配注入模式,选择入参个数最多的构造器创建bean |
没有提供构造器 | 手动装配为null,默认模式下最终会调用编译器自动生成的构造器 | 自动装配模式下走,最终调用自动生成的构造器创建bean |
多个有参构造器的情况,我们注意到在默认AUTOWIRE_NO注入模式下,Spring是会提示报错的。因为此种情况下Spring无法为多个模棱两可的构造器进行选择。
总结:
- 自动装配只要在手动装配集合不返回空时,就会继续走自动装配
- 手动装配是无论选择什么注入模式都会执行的,自动装配是不一定走的要根据手动装配的结果判定。但如果选择了自动注入那么就才一定走自动装配
- 手动装配和自动装配的关系,不是非此即彼,而是顺序的。先手动装配,成功了继续自动装配,否则直接手动装配结束就完成了
- 自动装配执行条件:1. 手动装配推断集合非空;2. 该bean注入模式为自动装配
如何设置为自动装配?
@Component
public class Person {
public Person() {
}
public Person(Car car) {
System.out.println("1");
}
public Person(Car car, House house) {
System.out.println("2");
}
}
@Component
public class LocalBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition person = ((GenericBeanDefinition) beanFactory.getBeanDefinition("person"));
person.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
}
}
- 这里只是将person的BeanDefinition的
AutowireMode
注入模式设置为AUTOWIRE_CONSTRUCTOR
,不影响其他的bean的注入模式。其他bean的注入模式依然为默认的AUTOWIRE_NO
源码及解析:
createBean() 源码分析
createBean() 中核心的创建源码是createBeanInstance(),所有的首次bean的创建都要走这个方法。
第二次bean创建时,如果单例,就不会进入到createBeanInstance()方法之前就会已经从一级或三级缓存中拿到对象;如果是原型,第二次也是会进入到createBeanInstance()方法的。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName())