Spring源码解读---推断构造方法解析

Posted *King*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码解读---推断构造方法解析相关的知识,希望对你有一定的参考价值。

Spring源码解读(7)—推断构造方法解析

一、Spring推断构造方法

在Spring中的一个bean需要实例化得到一个对象时就需要用到构造方法。

一般情况下,一个类只有一个构造方法,要么是无参的构造方法,要么是有参的构造方法:

如果只有一个无参的构造方法,那么实例化就只能使用这个构造方法,如果只有一个有参的构造方法,那么实例化时能使Spring会根据构造方法的参数信息去寻找bean,然后传给构造方法。

那么如果有多个构造方法呢?Spring在进行实例化之前该如何去确定使用哪个构造方法?

  1. 如果开发者指定了想用的构造的方法,那么就用这个构造方法,xml中可根据标签确定想要使用的构造方法的参数个数,也可通过@Autowired注解来指定构造方法。如果多个构造方法上写了@Autowired注解,则Spring会报错。
  2. 如果开发者没有指定想要使用的构造方法,Spring自动去选择无参的构造方法,如果没有无参的构造方法则报错。

二、推断构造方法的源码思路

  1. AbstractAutowireCapableBeanFactory类中的createBeanInstance()方法去创建一个Bean实例
  2. 根据BeanDefinition加载类得到Class对象
  3. 如果BeanDefinition绑定了一个Supplier,就调用Supplier的get方法得到一个对象并直接返回
  4. 如果BeanDefinition中存在factoryMethodName,那么就调用该工厂方法得到一个Bean对象并返回
  5. 如果BeanDefinition已经自动构造了,就调用autowireConstructor()自动构造一个对象
  6. 调用SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors()方法得到哪些构造方法是可用的
  7. 如果存在可用的构造方法,或当前BeanDefinition的autowired是AUTOWIRE_CONSTRUCTOR,或BeanDefinition中指定了构造方法参数值,或创建Bean时指定了构造方法参数值,就调用**autowireConstructor()方法自动构造一个对象
  8. 如果以上都不符合,就根据无参的构造方法实例化一个对象

autowireConstructor()

1、选检查是否指定了具体的构造方法和构造方法参数值,或在BeanDefinition中缓存了具体的构造方法或构造方法参数值,如果存在则直接使用构造方法进行实例化

2、如果没有确定的构造方法或构造方法参数值,则:找出类中所有的构造方法,如果只有一个无参的构造方法,则直接使用无参构造方法进行实例化;如果有多个可用的构造方法或当前Bean需要自动通过构造方法注入,则根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数,对所有的构造方法进行排序,参数个数多的在前面。遍历每个构造方法,如果不是调用getBean方法时所指定的构造方法参数值,则根据构造方法参数类型找值,如果调用getBean方法时所指定的构造方法参数值,则直接利用这些值,如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法是最佳的,所以如果有多个构造方法匹配了同样的值,这时就会用值和构造方法类型进行匹配程度打分,找到最匹配的。

@Bean的情况

Spring会把@Bean修饰的方法解析成BeanDefinition:

  1. 如果方法是static的,则解析出来的BeanDefiniton中:factoryBeanName为AppConfig所对应的beanName,比如“appConfig”,factoryMethodName为对应的方法名,如“aService”,factoryClass为AppConfig.class
  2. 如果方法不是static的,则解析出来的BeanDefinition中:factoryBeanName为null,factoryMethodName为对应的方法名,如“aService”,factoryClass也为AppConfig.class

在由@Bean生成的BeanDefinition中,有一个重要的属性isFactoryMethodUnique,表示 factoryMethod是不是唯一的,在普通情况下@Bean生成的BeanDefinition的 isFactoryMethodUnique为true,但是如果出现了方法重载,那么就是特殊的情况

@Bean
public static AService aService()
	return new AService();


@Bean
public AService aService(BService bService)
	return new AService();

虽然两个@Bean,但肯定只会生成一个aService的Bean,那么Spring在处理@Bean时,只会生成一个aService的BeanDefinition,比如Spring先解析到第一个@Bean,会生成一个BeanDefinition此时isFactoryMethodUnique为true,但是解析到第二个@Bean时,会判断出来 beanDefinitionMap中已经存在一个aService的BeanDefinition了,那么会把之前的这个 BeanDefinition的isFactoryMethodUnique修改为false,并且不会生成新的BeanDefinition了。

并且后续在根据BeanDefinition创建Bean时,会根据isFactoryMethodUnique来操作,如果为 true,那就表示当前BeanDefinition只对应了一个方法,那也就是只能用这个方法来创建Bean了, 但是如果isFactoryMethodUnique为false,那就表示当前BeanDefition对应了多个方法,需要和推 断构造方法的逻辑一样,去选择用哪个方法来创建Bean。

以上是关于Spring源码解读---推断构造方法解析的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码解读---推断构造方法解析

Spring源码解读---推断构造方法解析

OneFlow源码解析:算子签名的自动推断

Spring源码解读---启动过程源码解析

Spring源码解读---启动过程源码解析

Spring源码解读---启动过程源码解析