Spring源码解析(四) 初始化Bean工厂
SunRan

前言

初始化Bean工厂 这个名字起的好像有点大,在前面创建了Bean工厂后填充了一些属性,创建了BeanDifinition但是一直没有注入Bean。

本章Bean就将正式入住了。

建议结合 “Bean的生命周期” 这个问题一起思考

抽象流程

源码流程

finishBeanFactoryInitialization()

Bean 的生命周期

image-20220124221151814

源码

BeanDefinition 的合并机制

在创建工厂并读取Bean配置时会创建一个BeanDefinition对象,BeanDefinition是一个高级接口,准确来说时创建为了GenericBeanDefinition

在经历合并后会变成RootBeanDefinition

虽然执行了getMergedLocalBeanDefinition方法,但是正常来说这不是真正的第一次合并。

  • BeanDefinition 什么时候合并的?

    在调用BeanFactoryPostProcessor时就已经执行了。

    1
    2
    String[] postProcessorNames =
    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

    在根据类型获取postProcessorNames时,遍历所有的BeanDefinitionName获取合并后的BeanDefinition

    1
    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
  • 为什么要这么做?

    GenericBeanDefinition相比较Root多了一个ParentName的属性,用于记录Beanparent参数。

    通过GenericBeanDefinition先定义好对象的父子关系,后面的RootBeanDefinition根据前面所定义的父子关系去创建Bean,没有父类直接创建,存在父类递归的去创建父类(父类也可能存在父类)。

    如果不提前创建父子关系,很有可能出现创建子类时发现父类还没有创建此时就需要大量的判断和查询显然是没有两阶段机制优雅

FactoryBean 处理机制

FactoryBeanBeanFactory 看的很像,提供的服务也很像,但是底层时完全不同的。在 Spring 容器需要针对的做出一套处理机制/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 判断是否为FactoryBean
if (isFactoryBean(beanName)) {
// [1] 根据(&+beanName)的规则来获取对象
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// 进行类型转换
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
// 判断这个FactoryBean是否希望立即初始化
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
// 只有实现SmartFactoryBean才可以定义是否急迫
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
// [2] 如果希望急切的初始化,则通过beanName获取bean实例
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// [3] 如果beanName对应的bean不是FactoryBean,只是普通的bean,通过beanName获取bean实例
getBean(beanName);
}
  • [1] 根据(&+beanName)的规则来获取对象

    FactoryBean 是一个特殊的Bean

    FactoryBean 是一个特殊的Bean

    FactoryBean 是一个特殊的Bean

    ⚠️ 重要的事情说三遍,既然也是Bean也是需要交予Spring容器管理的。正是因为FactoryBean的特殊性,拥有了与其他Bean不同BeanName规则(需要前缀加一个&)

  • [2] 急切的初始化

    正常流程来说,FactoryBean 的对象在初始阶段是不会被注入到Spring容器的,需要在getBean()才会注入。

    如果isEagerInit = true 就会立刻注入。

    ⚠️ 此时注入的是实际的Bean,不是上面所注入的FactoryBean

  • [3] 普通的Bean

    不是FactoryBean正常执行getBean()即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # doGetBean
    // 前面说了 FactoryBean 在BeanName起名有独特的规范
    // 该方法就是去掉了&的前缀
    String beanName = transformedBeanName(name);
    Object bean;

    // 提前检查单例缓存中是否有手动注册的单例对象,跟循环依赖有关联
    Object sharedInstance = getSingleton(beanName);
    // 如果bean的单例对象找到了,且没有创建bean实例时要使用的参数
    if (sharedInstance != null && args == null) {
    // ...省略部分源码

    // 返回对象的实例
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    protected Object getObjectForBeanInstance(
    Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

    // name 如果是&作为前缀
    if (BeanFactoryUtils.isFactoryDereference(name)) {
    // 如果beanInstance是NullBean实例
    if (beanInstance instanceof NullBean) {
    // 返回beanInstance
    return beanInstance;
    }
    // 如果beanInstance不是FactoryBean实例
    if (!(beanInstance instanceof FactoryBean)) {
    // 抛出Bean不是一个Factory异常
    throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
    }
    // 如果mbd不为null
    if (mbd != null) {
    // 设置mbd是否是FactoryBean标记为true
    mbd.isFactoryBean = true;
    }
    // 返回beanInstance
    return beanInstance;
    }

    // 如果不是FactoryBean类型直接返回
    if (!(beanInstance instanceof FactoryBean)) {
    return beanInstance;
    }

    // 定义为bean公开的对象,初始化为null
    Object object = null;
    // 如果mbd不为null
    if (mbd != null) {
    // 更新mbd的是否是FactoryBean标记为true
    mbd.isFactoryBean = true;
    }
    else {
    // 从FactoryBean获得的对象缓存集中获取beanName对应的Bean对象
    object = getCachedObjectForFactoryBean(beanName);
    }
    // 如果object为null
    if (object == null) {
    // Return bean instance from factory.
    // 从工厂返回Bean实例
    // 将beanInstance强转为FactoryBean对象
    FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
    // Caches object obtained from FactoryBean if it is a singleton.
    // 如果是单例对象,则缓存从FactoryBean获得的对象、
    // 如果mbd为null&&该BeanFactory包含beanName的BeanDefinition对象。
    if (mbd == null && containsBeanDefinition(beanName)) {
    //获取beanName合并后的本地RootBeanDefintiond对象
    mbd = getMergedLocalBeanDefinition(beanName);
    }
    // 是否是'synthetic'标记:mbd不为null && 返回此bean定义是否是"synthetic"【一般是指只有AOP相关的prointCut配置或者
    // Advice配置才会将 synthetic设置为true】
    boolean synthetic = (mbd != null && mbd.isSynthetic());
    // 从BeanFactory对象中获取管理的对象.如果不是synthetic会对其对象进行该工厂的后置处理
    object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    // 返回为bean公开的对象
    return object;
    }

    getObjectForBeanInstance 方法可能出现三种情况:

    1. 普通的Bean对象:直接返回Instance
    2. 带有&符的FactoryBean:返回工厂Bean
    3. 不带&符的FactoryBean:返回对应工厂的实际Bean

Bean 是否正在创建中

1
2
3
4
5
6
7
8
9
10
11
# doGetBean
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}

protected boolean isPrototypeCurrentlyInCreation(String beanName) {
// 获取当前正在创建的bean名称【线程本地】
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}

❗返回True表示当前Bean正在创建

如果当前创建的Bean不为空且等于当前BeanName 或 当前正在创建的bean名称是Set集合,并包含该beanName

父工厂问题

通过BeanName获取Object时,如果存在父工厂且当前工厂不存在该BeanName时可能就嘀咕,它是不是存在父工厂了?

解决方案就是:通过递归的方式层层查找。

Bean存在依赖问题

例如在Xml定义Bean时可能设定一个 parent 属性:

1
2
3
4
5
6
7
8
<bean id="student" class="com.lksun.debug.entity.Student">
<property name="name" value="miaomiao"/>
<property name="age" value="8"/>
</bean>

<bean id="monitor" class="com.lksun.debug.entity.Monitor" parent="student" >
<property name="className" value="3-2"/>
</bean>

student作为monitor的父类或者依赖对象,先有鸡还是先有蛋就很重要了。

必须先创建了依赖Bean再创建当前对象。

解决方法同样使用递归,获取当前对象是否有依赖对象,然后层层判断

解析Bean Class

1
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

获取到了Class对象后只需要一步resolvedClass.newInstance();就可以获取到Object,但是Spring没有直接获取。

验证及准备覆盖的方法

todo ….

lookup-method replace-method

实际创建bean的方法 doCreateBean()

根据不同的策略创建Bean

1
instanceWrapper = createBeanInstance(beanName, mbd, args);

获取真实Bean对象

1
Object bean = instanceWrapper.getWrappedInstance();

加入缓存

关于解决循环依赖相关的问题后续着重讲

1
2
3
4
5
6
7
8
9
10
11
12
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));


protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}

判断一级缓存不存在当前Bean

然后执行:

1.将beanName,singletonFactory放到单例工厂的缓存(三级缓存)

2.在二级缓存删除当前Bean

3.将beanName添加已注册的单例集中

填充

1
populateBean(beanName, mbd, instanceWrapper);

执行初始化逻辑

1
exposedObject = initializeBean(beanName, exposedObject, mbd);

做了如下操作:

1.执行Aware接口处理器

2.BeanPostProcessor前置方法

3.调用初始化方法,先调用bean的InitializingBean接口方法,后调用bean的自定义初始化方法

4.BeanPostProcessor前置方法后置方法

注册Disposable

1
2
// 注册bean对象,方便后续在容器销毁的时候销毁对象
registerDisposableBeanIfNecessary(beanName, bean, mbd);

标记为“未创建”

1
2
// 创建单例后的回调,默认实现将单例标记为不在创建中
afterSingletonCreation(beanName);

添加到一级缓存

等一切都完成后添加到一级缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# getSingleton()
addSingleton(beanName, singletonObject);

protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 将映射关系添加到单例对象的高速缓存中
this.singletonObjects.put(beanName, singletonObject);
// 移除beanName在单例工厂缓存中的数据
this.singletonFactories.remove(beanName);
// 移除beanName在早期单例对象的高速缓存的数据
this.earlySingletonObjects.remove(beanName);
// 将beanName添加到已注册的单例集中
this.registeredSingletons.add(beanName);
}
}

1.先添加到一级缓存

2.在三级缓存移除

3.在二级缓存移除

4.保存到单例集合中

  • 本文标题:Spring源码解析(四) 初始化Bean工厂
  • 本文作者:SunRan
  • 创建时间:2022-01-21 16:10:52
  • 本文链接:https://lksun.cn/2022/01/21/Spring源码解析-四-初始化Bean工厂/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论