Spring Bean 生命周期简单分析

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

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

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

创建

Bean 的创建是其生命周期中最复杂的一步,这边对 getBean 方法跟踪,进入到了 AbstractBeanFactorydoGetBean 方法,该方法的内容就是构造 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. beforeSingletonCreationafterSingletonCreation 分别为标记 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