乐于分享
好东西不私藏

啃透Spring Bean生命周期:从源码层面堵上90%的Spring疑难杂症

啃透Spring Bean生命周期:从源码层面堵上90%的Spring疑难杂症

你有没有遇到过@Value注入null、自定义初始化方法不执行、AOP代理不生效的问题?90%的Spring使用坑都和Bean生命周期有关,今天咱们从Spring 5.x核心源码出发,把Bean从生到死的全流程扒得明明白白,看完再也不会被同类问题卡脖子。

一、先搞懂:Bean生命周期到底是啥

很多开发者对Spring Bean生命周期的认知只停留在「实例化-初始化-销毁」的模糊概念上,其实每个阶段都有明确的执行顺序和扩展点,也是Spring高扩展性的核心支撑。

整个流程可以分为4大核心阶段:实例化、属性填充、初始化、销毁,接下来我们逐个拆解源码逻辑。

二、源码拆解:实例化阶段

实例化是Bean生命周期的第一个阶段,本质就是调用构造方法创建一个空的Bean对象,还没有填充任何属性。核心逻辑在AbstractAutowireCapableBeanFactory#createBeanInstance方法中:

// AbstractAutowireCapableBeanFactory#createBeanInstance核心逻辑
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 1. 解析Bean对应的Class对象,校验是否可实例化
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }
    // 2. 如果配置了FactoryMethod,就用工厂方法实例化
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    // 3. 优先使用有参构造,没有的话用无参构造反射实例化
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }
    // 4. 无参构造实例化,我们平时最常用的实例化方式
    return instantiateBean(beanName, mbd);
}

重点注意:这个阶段生成的只是一个空的对象,所有属性都是默认值,@Autowired、@Value等注解还没有生效,不要在构造方法里依赖注入的属性,大概率会拿到null。

三、属性填充:依赖注入的核心逻辑

实例化完成之后就进入属性填充阶段,Spring会把Bean依赖的其他Bean、配置值等注入到对应的属性中,核心逻辑在AbstractAutowireCapableBeanFactory#populateBean方法:

// AbstractAutowireCapableBeanFactory#populateBean核心逻辑
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    // 遍历所有InstantiationAwareBeanPostProcessor,处理注解注入
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 重点:AutowiredAnnotationBeanPostProcessor在这里处理@Autowired、@Value注入
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                return;
            }
            pvs = pvsToUse;
        }
    }
    // 把解析完成的属性值设置到Bean实例中
    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

常见坑点:如果你的属性是static修饰的,Spring不会给静态属性注入值,因为Spring是给实例对象的属性注入,静态属性属于类本身,要注入的话可以通过set方法非静态化处理。

四、初始化阶段:功能增强的核心节点

属性填充完成之后进入初始化阶段,这是Spring扩展点最集中的阶段,AOP代理、自定义初始化逻辑都在这个阶段完成,核心逻辑在AbstractAutowireCapableBeanFactory#initializeBean方法:

// AbstractAutowireCapableBeanFactory#initializeBean核心逻辑
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    // 1. 执行Aware接口回调,把容器信息注入到Bean中
    invokeAwareMethods(beanName, bean);
    Object wrappedBean = bean;
    // 2. 执行所有BeanPostProcessor的postProcessBeforeInitialization方法
    // 比如CommonAnnotationBeanPostProcessor在这里处理@PostConstruct注解方法
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    // 3. 执行初始化方法:先执行InitializingBean的afterPropertiesSet,再执行自定义init-method
    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    } catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }
    // 4. 执行所有BeanPostProcessor的postProcessAfterInitialization方法
    // 重点:AOP动态代理就是在这里生成的,如果返回的是代理对象,后面使用的就是代理对象
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    return wrappedBean;
}

执行顺序牢记:Aware接口回调 → @PostConstruct方法 → InitializingBean.afterPropertiesSet → 自定义init-method方法 → AOP代理生成。如果你的初始化方法顺序不对,很大概率就是这里的顺序搞混了。

五、销毁阶段:资源释放的最后节点

当Spring容器关闭的时候,会触发Bean的销毁逻辑,主要是释放Bean占用的资源,比如数据库连接、文件流等,核心执行顺序是:先执行DisposableBean的destroy方法,再执行自定义的destroy-method方法。

需要注意的是,只有单例Bean会被Spring管理销毁逻辑,原型Bean Spring创建完成之后就不会再管理了,销毁逻辑需要开发者自己处理。

今天的源码拆解就到这啦,是不是感觉之前很多模模糊糊的Spring坑都有答案了?