Spring 构造器推断模型源码分析

前言:
大家都熟悉Spring的 IOCbean实例化 工作过程,那么当一个bean有多个构造器,Spring会在 IOCbean实例化 过程中选择哪一个最终作为创建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())
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值