【spring源码-5】bean的实例化(2)主逻辑

336 阅读5分钟

上一篇【spring源码-4】bean的实例化(1)准备工作

refresh()

image.png

551 行:实例化bean。

调用本类方法: image.png 调用到 DefaultListableBeanFactory 类中: image.png 871 行:拿到已经注册的 BeanDefinition 名称的集合。(前面xml解析已经将需要spring管理的bean注册到了bean工厂中)。
897 行

doGetBean

image.png image.png image.png image.png image.png 250 行:先从缓存中获取实例。
324 行:默认是单例的。

createBean(beanName, mbd, args)

image.png 516 行:doCreateBean(beanName, mbdToUse, args),调用本类方法,如下图。

doCreateBean(beanName, mbdToUse, args)

image.png 556 行:调用本类方法,如下图。


image.png image.png

1175 - 1177 行:实例化FactoryBean。
1200 - 1204 行:实例化带有 @Autowired 注解的 有参 构造函数。
1207 - 1210 行:实例化没有 @Autowired 注解的构造函数。
1213 行:实例化默认的构造函数。

实例化FactoryBean

方式一:调用其他类的非静态方法

类方法:
image.png 配置标签:
image.png
19 行:当前bean标签没有配置class属性;xml解析时会将 factory-bean 和 factory-method 的属性值设置给当前标签 BD对象相应的的属性中。如下所示:
image.png
接着调用到如下方法: image.png image.png 395 行:创建一个对bean实例的包装对象 BeanWrapperImpl。
403 行:判断当前BD对象有没有 factoryBeanName 显然是有的,就是标签设置的 factory-bean 属性值 “itman”
408 行:创建 FactoryBean 对象。
412 行:获取到 FactoryBean 对象的 class 这里就是 “com.springdemo.bean.ITMan”。
413 行:将是否是静态变量设置为 false。
接上图,是一个方法: image.png 466 行:获取到当前 class 的所有方法。
467 - 472 行:循环所有的方法,找出 非静态的 并且方法名就是设置在标签 factory-method 属性的方法。
483 行:如果找到的目标方法只有一个,先调用 instantiate 方法(就是反射调用),然后将返回的对象设置给BeanWrapperImpl。
484 行:方法返回 BeanWrapperImpl。


方式二:调用本类的非静态方法

类方法:
image.png
配置标签:
image.png

还是上面方式一的那个方法。为方便阅读,再次贴图:
image.png image.png 417 - 418 行:如果 bean 标签没有设置 factory-bean 属性也没有设置 class 属性,直接抛异常。
412 行:获取到 class。
413 行:将是否是静态变量设置为 true。
466 - 484 行:实例化与方式一一致。


通过构造方法实例化bean

还是上面 实例化FactoryBean 的方法: image.png 1200 - 1204 行:通过构造方法实例化bean入口。分两步,先找出目标构造函数,再反射调用它创建实例。

实例化带有 @Autowired 注解的 有参 构造函数

类信息:
image.png

1200 行:调用本类方法。 image.png 方法描述:

BeanPostProcessor 的应用
循环所有的BeanPostProcessor类,找出 SmartInstantiationAwareBeanPostProcessor 类型的BeanPostProcessor,并调用它的 determineCandidateConstructors() 方法。

这里调用到 AutowiredAnnotationBeanPostProcessor 类的 determineCandidateConstructors() 方法。 image.png image.png image.png image.png

只有一个带有 @Autowired 注解的 有参 构造函数

262 - 293 行:对Lookup 注解的支持。
304 行:获取到当前类所有的构造方法。
316 行:循环构造方法集合。
323 行:获取到当前构造方法的 @Autowired 注解信息。
344 行:获取到 @Autowired 注解的 required 属性的值(默认为true)。
352 行:将当前构造方法赋值给 requiredConstructor。
354 行:将当前构造方法添加到集合中。

有多个带有 @Autowired 注解的 有参 构造函数

类信息: image.png
此时运行会报错:
Snipaste_2021-11-06_16-22-32的副本.png 338 行:(第一次循环时在352行记录了一个构造函数),在第二次循环时,requiredConstructor 不为空,直接抛出异常。

解决方案:每次循环时都不给 requiredConstructor 赋值,只需要设置@Autowired 注解的 required 属性的值为false即可。如下:

image.png


实例化没有 @Autowired 注解的构造函数

类信息:
image.png

image.png image.png

方法总结:
如果只有一个没有 @Autowired 注解的构造函数,它就是最终目标。
如果有多个,会返回null,最终会调用到 1213 行走默认的构造,此时如果没有写默认构造就会报错。


此时构造函数已经找出,然后调用它创建实例。还是这个方法: image.png 1203 行:调用本类方法 image.png 然后调用到 ConstructorResolver 类的 autowireConstructor() 方法。 image.png image.png image.png image.png

方法描述:

  1. 一个构造函数,直接反射调用创建实例。
  2. 多个构造函数,根据构造函数的形参数量排序,最终会调用到形参数量最多的那个。

总结

bean的实例化有两种方式:

  • FactoryBean
    在XML配置文件 bean 标签中设置 factory-bean 和 factory-method 属性。
    1. 调用其他类中非静态方法。
    2. 调用本类中静态方法。
  • 通过构造函数实例化bean
    1. 先选择带有 @Autowired 注解的构造函数,若存在多个,可以将 required 设置为false,spring 会择>调用形参数量最多的那个实例化bean。
    2. 若不存在带有 @Autowired 注解的构造函数,spring 会选择唯一的构造,如果存在多个,spring 会选择>调用默认的构造函数实例化bean,此时如果没有写默认的就会报错。
    3. 若类中没有自定义的构造函数,spring 会调用默认构造函数实例化 bean。

注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。

下一篇【spring源码-6】bean的实例化(3)注解收集、依赖注入(DI)