本文主要基于 Spring 5.0.6.RELEASE
摘要: 原创出处 http://cmsblogs.com/?p=todo 「小明哥」,谢谢!
作为「小明哥」的忠实读者,「老艿艿」略作修改,记录在理解过程中,参考的资料。
#createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)
方法,用于实例化 Bean 对象。它会根据不同情况,选择不同的实例化策略来完成 Bean 的初始化,主要包括:
- Supplier 回调:
#obtainFromSupplier(final String beanName, final RootBeanDefinition mbd)
方法。 - 工厂方法初始化:
#instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs)
方法。 - 构造函数自动注入初始化:
#autowireConstructor(final String beanName, final RootBeanDefinition mbd, Constructor<?>[] chosenCtors, final Object[] explicitArgs)
方法。 - 默认构造函数注入:
#instantiateBean(final String beanName, final RootBeanDefinition mbd)
方法。
在上篇博客(《【死磕 Spring】—— IoC 之加载 bean:创建 bean(二)》) 中,分析了前两种 Supplier 回调和工厂方法初始化。这篇博文,分析后两种构造函数注入。
1. autowireConstructor
这个初始化方法,我们可以简单理解为是带有参数的构造方法,来初始化 Bean 对象。代码段如下:
// AbstractAutowireCapableBeanFactory.java |
- 代码与
#instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs)
方法,一样,又长又难懂。但是如果理解了#instantiateUsingFactoryMethod(...)
方法的初始化 bean 的过程,那么#autowireConstructor(...)
方法,也不存在什么难的地方了。 - 一句话概括:首先确定构造函数参数、构造函数,然后调用相应的初始化策略进行 bean 的初始化。关于如何确定构造函数、构造参数,该部分逻辑和
#instantiateUsingFactoryMethod(...)
方法,基本一致。所以这里不再重复阐述了,具体过程请移步【死磕 Spring】—— IoC 之加载 bean:创建 bean(二),这里我们重点分析初始化策略。
1.1 instantiate
// BeanUtils.java |
<1>
首先,是获取实例化 Bean 的策略 InstantiationStrategy 对象。<2>
然后,调用其#instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner, Constructor<?> ctor, Object... args)
方法,该方法在 SimpleInstantiationStrategy 中实现。代码如下:// SimpleInstantiationStrategy.java
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
final Constructor<?> ctor, Object... args) {
// <x1> 没有覆盖,直接使用反射实例化即可
if (!bd.hasMethodOverrides()) {
if (System.getSecurityManager() != null) {
// 设置构造方法,可访问
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(ctor);
return null;
});
}
// 通过 BeanUtils 直接使用构造器对象实例化 Bean 对象
return BeanUtils.instantiateClass(ctor, args);
} else {
// <x2> 生成 CGLIB 创建的子类对象
return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
}
}<x1>
如果该 bean 没有配置lookup-method
、replaced-method
标签或者@Lookup
注解,则直接通过反射的方式实例化 Bean 对象即可,方便快捷。详细解析,见 「1.1.1 反射创建 Bean 对象」 中。<x2>
但是,如果存在需要覆盖的方法或者动态替换的方法时,则需要使用 CGLIB 进行动态代理,因为可以在创建代理的同时将动态方法织入类中。详细解析,见 「1.1.2 CGLIB 创建 Bean 对象」 中。
1.1.1 反射创建 Bean 对象
调用工具类 BeanUtils 的 #instantiateClass(Constructor<T> ctor, Object... args)
方法,完成反射工作,创建对象。代码如下:
// BeanUtils.java |
1.1.2 CGLIB 创建 Bean 对象
// SimpleInstantiationStrategy.java |
方法默认是没有实现的,具体过程由其子类
org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy
来实现。代码如下:// CglibSubclassingInstantiationStrategy.java
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
return instantiateWithMethodInjection(bd, beanName, owner, null);
}
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Constructor<?> ctor, Object... args) {
// Must generate CGLIB subclass...
// 通过CGLIB生成一个子类对象
return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}创建一个 CglibSubclassCreator 对象,后调用其
#instantiate(Constructor<?> ctor, Object... args)
方法,生成其子类对象。代码如下:// CglibSubclassingInstantiationStrategy.java
public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
// 通过 Cglib 创建一个代理类
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
// 没有构造器,通过 BeanUtils 使用默认构造器创建一个bean实例
if (ctor == null) {
instance = BeanUtils.instantiateClass(subclass);
} else {
try {
// 获取代理类对应的构造器对象,并实例化 bean
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
instance = enhancedSubclassConstructor.newInstance(args);
} catch (Exception ex) {
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
}
}
// SPR-10785: set callbacks directly on the instance instead of in the
// enhanced class (via the Enhancer) in order to avoid memory leaks.
// 为了避免 memory leaks 异常,直接在 bean 实例上设置回调对象
Factory factory = (Factory) instance;
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
return instance;
}- 到这类 CGLIB 的方式分析完毕了,当然这里还没有具体分析 CGLIB 生成子类的详细过程,具体的过程等后续分析 AOP 的时候再详细地介绍。
2. instantiateBean
// AbstractAutowireCapableBeanFactory.java |
- 这个方法,相比于
#instantiateUsingFactoryMethod(...)
、#autowireConstructor(...)
方法,实在是太简单了,因为,它没有参数,所以不需要确认经过复杂的过来来确定构造器、构造参数,所以这里就不过多阐述了。
2.1 instantiate
// SimpleInstantiationStrategy.java |
3. 小结
对于 #createBeanInstance(...)
方法而言,他就是选择合适实例化策略来为 bean 创建实例对象,具体的策略有:
- Supplier 回调方式
- 工厂方法初始化
- 构造函数自动注入初始化
- 默认构造函数注入。
其中,工厂方法初始化和构造函数自动注入初始化两种方式最为复杂,主要是因为构造函数和构造参数的不确定性,Spring 需要花大量的精力来确定构造函数和构造参数,如果确定了则好办,直接选择实例化策略即可。
当然,在实例化的时候会根据是否有需要覆盖或者动态替换掉的方法,因为存在覆盖或者织入的话需要创建动态代理将方法织入,这个时候就只能选择 CGLIB 的方式来实例化,否则直接利用反射的方式即可,方便快捷。
到这里 #createBeanInstance(...)
的过程就已经分析完毕了,下篇介绍 #doCreateBean(...)
方法中的第二个过程:循环依赖的处理。其实,在整个 bean 的加载过程中都涉及到了循环依赖的处理,所以下面分析并不是仅仅只针对 #doCreateBean(...)
方法中的循环依赖处理,而是 Spring 在整个 IoC 体系中是如何解决循环依赖的。