1 简介
本文将详细分析doCreateBean
方法中的一个重要的调用,即createBeanInstance
方法。先来了解一下方法的大致脉络。
1 |
// AbstractAutowireCapableBeanFactory.java protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 解析 bean ,将 bean 类名解析为 class 引用。 /* // <1> 如果存在 Supplier 回调,则使用给定的回调方法初始化策略 // <2> 使用 FactoryBean 的 factory-method 来创建bean 对象,支持静态工厂和实例工厂 // <3> 快捷路径 // <4> 由后置处理器决定返回哪些构造方法 // <4.1> 选择构造方法,创建 Bean 。 // <4.2> 有参数时,又没获取到构造方法,则只能调用无参构造方法来创建实例了(兜底方法) |
---|
整体的思路如下:
<1>
处,如果存在 Supplier 回调,则调用obtainFromSupplier
方法,进行初始化。<2>
处,如果存在工厂方法,则使用工厂方法进行初始化。<3>
处,如果缓存中存在,即已经解析过了,则直接使用已经解析了的。根据constructorArgumentsResolved
参数来选择:<3.1>
处,使用构造函数自动注入。调用autowireConstructor(String beanName, RootBeanDefinition mbd, Constructor[] ctors, Object[] explicitArgs)
方法<3.2>
处,使用默认构造函数。调用instantiateBean(final String beanName, final RootBeanDefinition mbd)
方法。
<4>
处,如果缓存中没有,则通过组合条件决定使用哪种方式构建 bean 对象。<4.1>
处,如果存在参数,则使用相应的带有参数的构造函数。<4.2>
处,否则,使用默认构造函数。
所以,这里有三种构造 bean 对象的方式,如下:
- Supplier 回调。
- 通过“工厂方法”的方式构造 bean 对象。
- 通过“构造方法自动注入”的方式构造 bean 对象。
- 通过“默认构造方法”的方式构造 bean 对象。
下面将会分析第1种和第3种构造bean对象的方法。
2 通过Supplier 回调创建 bean 对象
2.1 Supplier
介绍
Supplier 是什么呢?,Supplier是一个接口,位于java.util.function
包下。代码如下:
1 |
public interface Supplier<T> { T get(); } |
---|
Supplier 接口仅有一个功能性的 #get()
方法,该方法会返回一个 <T>
类型的对象,有点儿类似工厂方法。那这个接口有什么作用?用于指定创建 bean 的回调。如果我们设置了这样的回调,那么其他的构造器或者工厂方法都会没有用。
Spring 提供了相应的 setter 方法,用于设置Supplier 参数,代码如下:
1 |
// AbstractBeanDefinition.java /** public void setInstanceSupplier(@Nullable Supplier<?> instanceSupplier) { |
---|
在构造 BeanDefinition
对象的时候,设置了 instanceSupplier
该值,代码如下(以 RootBeanDefinition
为例):
1 |
// RootBeanDefinition.java public <T> RootBeanDefinition(@Nullable Class<T> beanClass, String scope, @Nullable Supplier<T> instanceSupplier) { |
---|
2.2 Supplier 回调
在createBeanInstance
方法中,对应调用代码如下:
1 |
Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); |
---|
先从 BeanDefinition
中获取 Supplier 对象。如果不为空,则调用 obtainFromSupplier
方法。代码如下:
1 |
// AbstractAutowireCapableBeanFactory.java /** protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) { // 未创建 Bean 对象,则创建 NullBean 对象 |
---|
流程如下:
<1>
处,调用 Supplier 的get()
方法,获得一个 Bean 实例对象。<2>
处,根据该实例对象构造一个BeanWrapper
对象bw
。<3>
处, 初始化该对象。
3 通过构造方法自动注入创建 bean 对象
这个初始化方法,我们可以简单理解为是带有参数的构造方法,来初始化 Bean 对象。代码逻辑较为复杂,需要大家耐心阅读。代码段如下:
1 |
// AbstractAutowireCapableBeanFactory.java protected BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) { // 创建 ConstructorResolver 对象,并调用其 autowireConstructor 方法 |
---|
1 |
// ConstructorResolver.java public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, // 封装 BeanWrapperImpl 对象,并完成初始化 // 获得 constructorToUse、argsHolderToUse、argsToUse // 确定构造参数(argsToUse) // 没有缓存,则尝试从配置文件中获取参数 // 创建 Bean // 是否需要解析构造器 // 对构造函数进行排序处理 // 最小参数类型权重 // 迭代所有构造函数 // 如果已经找到选用的构造函数或者需要的参数个数小于当前的构造函数参数个数,则终止。 if (constructorToUse != null && argsToUse.length > paramTypes.length) { /* // 参数持有者 ArgumentsHolder 对象 /* /* /* // 若上面未能筛选出合适的构造方法,这里将抛出 BeanCreationException 异常 /* if (explicitArgs == null) { // 创建 Bean 对象,并设置到 bw 中 |
---|
上面的方法逻辑比较复杂,做了不少事情,该方法的核心逻辑是根据参数值类型筛选合适的构造方法。解析出合适的构造方法后,剩下的工作就是构建 bean 对象了,这个工作交给了实例化策略去做。上面方法的整体流程为:
- 创建
BeanWrapperImpl
对象。 - 解析构造方法参数,并算出
minNrOfArgs
。 - 获取构造方法列表,并排序。
- 遍历排序好的构造方法列表,筛选合适的构造方法。
- 获取构造方法参数列表中每个参数的名称。
- 再次解析参数,此次解析会将value 属性值进行类型转换,由 String 转为合适的类型。
- 计算构造方法参数列表与参数值列表之间的类型差异量,以筛选出更为合适的构造方法。
- 缓存已筛选出的构造方法以及参数值列表,若再次创建 bean 实例时,可直接使用,无需再次进行筛选。
- 使用初始化策略创建 bean 对象。
- 将 bean 对象放入
BeanWrapperImpl
对象中,并返回该对象。
下一小节将分析instantiate
方法,以及通过反射和CGLIB 创建 Bean 对象。
4 instantiate
方法
instantiate
方法,对应上面代码的278行,代码如下:
1 |
//ConstructorResolver.java private Object instantiate( try { |
---|
上面第18行的instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse)
代码如下:
1 |
// SimpleInstantiationStrategy.java @Override |
---|
<1>
处,如果该 bean 没有配置lookup-method
、replaced-method
标签或者@Lookup
注解,则直接通过反射的方式实例化 Bean 对象即可。<2>处
,使用 CGLIB 进行动态代理,因为可以在创建代理的同时将动态方法织入类中。
4.1 反射创建 Bean 对象
调用工具类 BeanUtils
的 instantiateClass(Constructor ctor, Object... args)
方法,完成反射工作,创建对象。代码如下:
1 |
// BeanUtils.java public static <T> T instantiateClass(Constructor<T> ctor, Object… args) throws BeanInstantiationException { |
---|
4.2 CGLIB 创建 Bean 对象
1 |
// SimpleInstantiationStrategy.java protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { |
---|
方法默认是没有实现的,具体过程由其子类CglibSubclassingInstantiationStrategy
来实现。代码如下:
1 |
// CglibSubclassingInstantiationStrategy.java @Override |
---|
创建一个 CglibSubclassCreator
对象,后调用其 #instantiate(Constructor ctor, Object... args)
方法,生成其子类对象。代码如下:
1 |
// CglibSubclassingInstantiationStrategy.java public Object instantiate(@Nullable Constructor<?> ctor, Object… args) { |
---|
小结
createBeanInstance
已经分析完毕了,其中工厂方法初始化和默认构造函数注入没有分析。有一个很重要的原因就是,构造函数自动注入初始化即autowireConstructor
的方法实在是太长了,逻辑很复杂,分析完已经晕了,哈哈。很感谢一些博主,因为他们的博文,我看起源码来才能更快的理解。继续加油!