Spring Bean 生命周期简单分析

容器是 Spring 设计中一个核心组件,它负责管理 Bean 实例,并提供了接口 BeanFactory 使用。

网上对这个有太多分析的文章了,但大多繁琐不堪,不易新手理解,这里就只对关键步骤做个简单分析。

文章中所研究的 Spring 版本为 5.1.4

创建

Bean 的创建是其生命周期中最复杂的一步,这边对 getBean 方法跟踪,进入到了 AbstractBeanFactory 的 doGetBean 方法,该方法的内容就是构造 Bean 的主要流程,这里只将关键的步骤提取出来。

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    final String beanName = transformedBeanName(name); // 解析 Bean 名称
    
    Object bean;

    Object sharedInstance = getSingleton(beanName); // 1. 获取 Bean 实例或构造工厂
    if (sharedInstance != null && args == null) {
        // 这里主要是对构造工厂进行创建实例
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    } else {
        BeanFactory parentBeanFactory = getParentBeanFactory();
        // 检查父级构造工厂是否包含实例,是则交由父级工厂创建返回
        ...

        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        // 初始化当前 Bean 所依赖的 Bean
        ...


        // 2. 根据 Bean 的类型选择构造方式,这里分析单例模式
        sharedInstance = getSingleton(beanName, () -> {
            try {
                return createBean(beanName, mbd, args); // 具体构造实例的逻辑
            }
            catch (BeansException ex) {
                destroySingleton(beanName);
                throw ex;
            }
        });
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }

    // 类型检查和转换
    ...
    return (T) bean;
}

获取单例

其实整个流程十分复杂,这里也能够看出 Spring 的严谨性。首先跟进 1. getSingleton(),它的逻辑虽然简单,但其实是对解决循环依赖问题非常关键的一步。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

这里有两个解决循环引用的要点,这里先知道就行。

  1. 一是 isSingletonCurrentlyInCreation(beanName),这是标记了一个 Bean 正处于构造阶段中。

  2. 还有一个是 this.singletonFactories.get(beanName),这里返回的是 Bean 实例的构造工厂,需要在其他位置通过调用 addSingletonFactory 加入进来。

创建 Bean 实例

创建实例调用的内容非常多,这边主要讲下构造、注入、处理器的过程。

首先看到 2. getSingleton(),这里需要关注的只有这几步,

  1. beforeSingletonCreation 和 afterSingletonCreation 分别为标记 Bean 在创建中和移除标记

  2. 使用前面的 createBean 创建实例。

  3. addSingleton 则是将创建的实例加入到容器中。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    beforeSingletonCreation(beanName);
    try {
        singletonObject = singletonFactory.getObject();
        newSingleton = true;
    }
    finally {
        afterSingletonCreation(beanName);
    }
    if (newSingleton) {
        addSingleton(beanName, singletonObject);
    }
    return singletonObject;
}

继续分析 createBean,其实里面主要是委托了 doCreateBean 方法来创建实例,解决循环引用的关键点就是这里的 addSingletonFactory,使得 Bean 在创建阶段就提供依赖引用。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {

    // 创建实例,会涉及构造器注入
    BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
    final Object bean = instanceWrapper.getWrappedInstance();

    // 缓存实例引用
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    Object exposedObject = bean;

    // 初始化实例
    populateBean(beanName, mbd, instanceWrapper);
    exposedObject = initializeBean(beanName, exposedObject, mbd);

    return exposedObject;
}

初始化

当 Bean 在 doCreateBean 中完成了实例的创建,接着就会对实例进行属性注入、调用初始化方法、执行前置/后置处理器,而后将实例加入到 Spring 容器中,就完成了一个 Bean 的创建阶段。

这个过程也可以通过 AutowireCapableBeanFactory#initializeBean 来完成。

销毁

一个 Bean 实例的销毁可以随着 Spring 生命周期结束而触发,也可以通过调用 AutowireCapableBeanFactory 中的 destroyBean 来进行。

他将构造一个 DisposableBeanAdapter 来执行不同实例的销毁流程,这里的代码流程清晰明了。

public void destroy() {
    for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
        processor.postProcessBeforeDestruction(this.bean, this.beanName); // 执行前置销毁处理器
    }

    // 执行实现 DisposableBean 的销毁方法
    ((DisposableBean) this.bean).destroy();

    // 执行自定义销毁方法
    invokeCustomDestroyMethod(this.destroyMethod);
}

时序图

用时序图展示 创建初始化 的流程以便更好的理解。

spring-beanfactory