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;
}
这里有两个解决循环引用的要点,这里先知道就行。
- 
一是
isSingletonCurrentlyInCreation(beanName),这是标记了一个 Bean 正处于构造阶段中。 - 
还有一个是
this.singletonFactories.get(beanName),这里返回的是 Bean 实例的构造工厂,需要在其他位置通过调用addSingletonFactory加入进来。 
创建 Bean 实例
创建实例调用的内容非常多,这边主要讲下构造、注入、处理器的过程。
首先看到 2. getSingleton(),这里需要关注的只有这几步,
- 
beforeSingletonCreation和afterSingletonCreation分别为标记 Bean 在创建中和移除标记 - 
使用前面的
createBean创建实例。 - 
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);
}
时序图
用时序图展示 创建初始化 的流程以便更好的理解。
