图解Spring源码3-Spring Bean的生命周期

294 阅读14分钟

>>>点击去看配套视频<<<

涉及Spring源码相关类和接口,代码浓度🌟🌟🌟🌟 理解大于记忆

从一个例子开始

小陈将开店规格单邮寄到咖啡加盟总部后,总部的设备管理中心按照规定的开店标准化流程,根据总部规范进行审计,然后进行选址装修、安装设备(安装完成后技术专家还会进行设备固件升级)、开业前检查等步骤后小陈可以正常营业了,工作人员还告知小陈后期如果关店的话,总部会进行设备的回收。

Bean的生命周期概念引入

上面说到的开店标准化流程,对应了Spring中的Bean的生命周期

  1. 填写开店规格单:小陈填写《开店规格单》(Bean元数据),总部解析并注册到设备管理中心(见Spring Bean元数据体系与Spring容器章节)

  2. 总部规范审计​:设备中心专员收到申请后,先根据《设备白皮书》调整设备配置标准(如修改咖啡机型号参数),这对应BeanFactoryPostProcessor对元数据的预处理。

  3. 店面基础装修(实例化)​:施工队按调整后的标准进行场地硬装,相当于Spring创建Bean实例。

  4. 设备专家调试(前置处理)​:安装咖啡机后,技术专家进行固件升级(@PostConstruct前执行自定义逻辑),类似BeanPostProcessor前置处理

  5. 开业资质检查​:调试完成后进行食品安全检测,对应Bean的初始化方法

  6. 设备性能优化(后置处理)​:正式营业前对咖啡机做压力测试(BeanPostProcessor后置处理)

  7. 正常营业(Bean就绪)​

  8. 关店回收(@PreDestroy)​:总部按标准流程拆除回收设备

BeanFactoryPostProcessor是在容器加载Bean定义之后,实例化Bean之前执行的,用来修改Bean的定义。

而BeanPostProcessor则是在Bean实例化之后,初始化前后进行干预

理解BeanFactoryPostProcessor & BeanPostProcessor

3.1 BeanFactoryPostProcessor:设备管理中心的标准化审计流程

  • 作用阶段:在容器加载Bean的定义​(BeanDefinition)之后、但Bean实例化之前。

  • 类比例子:小陈提交开店规格单后,总部设备管理中心的审计流程。

    • 审计流程:总部根据规范审核小陈的规格单(如设备型号、装修方案等),可能会调整参数(如强制使用指定咖啡机型号)。
    • 对应到Spring:BeanFactoryPostProcessor可以修改Bean的定义(例如将配置中的占位符替换为实际值,或强制某些属性值)。
  • 关键点:

    • 影响的是Bean的配置模板​(未实例化)。
    • 全局性操作,通常用于统一调整所有Bean的定义。

BeanFactoryPostProcessor是对整个设备管理中心的扩展性接口,可以调整BeanFactoryProcessor

@FunctionalInterface
public interface BeanFactoryPostProcessor {
    // 调整整个beanFactory
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

3.2 BeanPostProcessor:设备的安装、升级和开业检查

  • 作用阶段:在Bean实例化之后,分别在初始化方法(init)的前后介入。

  • 类比例子:设备安装后的固件升级和开业前检查。

    • 安装设备:实例化Bean(咖啡机、收银台等)。
    • 固件升级(初始化前)​:技术专家在设备安装后、正式开业前升级固件(如调整咖啡机参数)。
    • 开业检查(初始化后)​:确保设备正常运行(如测试咖啡机是否出杯正常)。
    • 对应到Spring:BeanPostProcessor可以在初始化前后修改Bean实例(如注入代理、资源或执行校验)。
  • 关键点:

    • 影响的是已创建的Bean实例。
    • 针对每个Bean单独处理,通常用于增强或监控Bean。
public interface BeanPostProcessor {

    // 在bean初始化前处理
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       return bean;
    }
    // 在bean初始化后处理
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
       return bean;
    }

}

为什么要有Bean生命周期

Spring 的 Bean 生命周期机制是为了解决 对象管理复杂性 和 资源控制权分离 的核心问题。通过标准化的生命周期流程,Spring 实现了对 Bean 的 全流程托管,同时为开发者提供了灵活的 扩展点,使其既能享受框架的自动化管理,又能深度介入关键环节。

对象管理的复杂性

  • 传统问题:在没有框架的情况下,开发者需要手动管理对象的创建、依赖注入、初始化和销毁。例如:
// 手动创建对象、依赖注入、初始化
UserService userService = new UserService();
userService.setUserDao(new UserDao());
userService.init();
// 使用后手动销毁
userService.destroy();
  • Spring 的解决:将对象的创建、依赖注入、初始化和销毁交给容器统一管理,开发者只需声明 Bean 的配置。

资源控制权分离

  • 传统问题:对象依赖的资源(如数据库连接、线程池)需要自行获取和释放,例如:
public class DataSource {
    public void connect() { /* 获取连接 */ }
    public void close() { /* 释放连接 */ }
}
  • Spring 的解决:通过生命周期回调(如 @PostConstruct、@PreDestroy),将资源初始化和释放逻辑集中在 Bean 内部,与业务代码解耦。

Spring 生命周期&设计理念

Spring 生命周期设计理念主要有两部分:标准化的生命周期阶段 和 分层扩展点

标准化的生命周期阶段

在这里插入图片描述

  1. 围绕实例化的扩展点

Spring中的Bean也是Java中对象,因此Spring针对实例化前后设置了一系列扩展点

  1. 围绕初始化点扩展点

初始化是指bean实例化后,需要执行一些特定逻辑(比如连接池建立连接)的过程

Spring可以指定初始化方法,并在初始化前后进行扩展操作。

  1. 销毁

当spring容器关闭时回调单例bean的销毁方法

生命周期分层扩展点

4.2.1 闭环在bean本身的扩展点

spring中可以使用@PostConstruct定义在bean构造完成后回调方法,以及使用@PreDestroy定义在容器销毁前执行的方法,Spring容器会自动进行反射调用

有趣的是@PostConstruct和@PreDestroy并不是Spring定义的注解,而是Java EE 标准规范(JSR-250)​定义的注解,通过支持标准注解,Spring 可以与其他遵循 Java EE 规范的框架(如 Jakarta EE)无缝集成,降低技术栈迁移成本。 例如:从传统 Java EE 应用迁移到 Spring Boot 时,原有代码中的 @PostConstruct 注解无需修改即可复用。 <img src="image/Yn7Bba06moVHg7xb9focSxhtn5E.png" alt="image" style="max-width:100%;height:auto;display:block;margin:0 auto;" loading="lazy" />

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 定义 CoffeeShop Bean,指定初始化/销毁方法 -->
    <bean id="coffeeShop" class="com.example.CoffeeShop"
          init-method="openShop" 
          destroy-method="closeShop">
    </bean>
</bean
AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(CoffeeShop.class);
beanDefinition.setInitMethodName("init");
beanDefinition.setDestroyMethodName("destroy");

如上展示了,如何通过xml和调用BeanDefinition接口方法的方式来指定初始化和销毁方法。即使是xml最终也还是记录到BeanDefinition实例中。Spring容器会在对应的实际进行反射调用

还有@Bean 注解的也可以指定初始化和销毁方法,后续讲解@Bean 注解的时候再详细介绍,这里不做过多展开 <img src="image/FTyebsTsyoDSIUxzBYfcYAxfnFh.png" alt="image" style="max-width:100%;height:auto;display:block;margin:0 auto;" loading="lazy" /> <!-- 图片未成功捕获 -->

实现afterPropertiesSet方法,可以自定义初始化逻辑,当前Spring实例化bean并且完成属性注入后,会回调afterPropertiesSet(强转为InitializingBean类型,调用afterPropertiesSet方法,无需反射)

InitializingBean是Spring提供的标准化接口,毕竟目前很少使用xml来定义bean的初始化方法

在这里插入图片描述

实现destory方法,可以自定义销毁逻辑,当前Spring容器销毁时,会毁掉destory方法(强转为DisposableBean类型,调用destory方法,无需反射)

DisposableBean是Spring提供的标准化接口,毕竟目前很少使用xml来定义bean的销毁方法 在这里插入图片描述

实现afterSingletonsInstantiated方法,Spring容器初始化完所有单例bean方法后会统一的回调所有单例bean的afterSingletonsInstantiated方法

和InitializingBean不同,InitializingBean是每一个bean初始化完成后进行回调,无论是否单例,SmartInitializingSingleton是所有单例bean初始化完成后,轮流调用每一个单例bean的afterSingletonsInstantiated方法

Aware 意味感知,Spring提供实现Aware接口来感知容器的能力 <img src="image/Lba9b70fkoVzZ9xT1QJcRylAnDb.png" alt="image" style="max-width:100%;height:auto;display:block;margin:0 auto;" loading="lazy" /> <!-- 图片未成功捕获 -->

在Spring框架中,Aware接口是一组用于让Bean感知容器特定功能的接口。它们允许Bean在初始化阶段获取Spring容器提供的底层资源或上下文信息,从而实现更灵活的交互。

小陈的咖啡店需要知道总部的联系方式,需要知道设备管理中心的联系方式,如何实现呢?

实现Aware类型接口,Spring会回调对应的方法


  • 作用:注入ApplicationContext实例,使Bean能直接操作容器。

  • 使用场景:动态获取其他Bean、访问环境变量、发布事件等。

  • 示例:

public class CoffeeShop implements ApplicationContextAware {
    // 总部联系方式写在墙上
    private ApplicationContext context;
    
    @Override
    public void setApplicationContext(ApplicationContext context) {
        this.context = context;
    }
    
    public void useContext() {
        AnotherBean bean = context.getBean(AnotherBean.class);
    }
}
  • 作用:注入Bean在容器中的名称(ID或别名)。

  • 使用场景:日志记录、根据Bean名称动态配置行为。

public class MyBean implements BeanNameAware {
    private String beanName;
    
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}
  • 作用:注入BeanFactory实例,提供更底层的容器操作。

  • 使用场景:检查Bean作用域、延迟初始化其他Bean。

  • 示例:

public class MyBean implements BeanFactoryAware {
    private BeanFactory factory;
    
    @Override
    public void setBeanFactory(BeanFactory factory) {
        this.factory = factory;
    }
    
    public void checkScope() {
        boolean isSingleton = factory.isSingleton("anotherBean");
    }
}
  • 作用:注入Environment对象,用于访问配置属性(如环境变量、配置文件)。

  • 使用场景:读取外部化配置。

  • 示例:

public class MyBean implements EnvironmentAware {
    private Environment env;
    
    @Override
    public void setEnvironment(Environment env) {
        this.env = env;
    }
    
    public String getProperty() {
        return env.getProperty("my.config.key");
    }
}
  • ResourceLoaderAware:获取ResourceLoader,用于加载类路径或文件系统资源。

  • MessageSourceAware:注入MessageSource,支持国际化消息处理。

  • ApplicationEventPublisherAware:发布应用事件。


  • 调用阶段:在Bean的依赖注入(属性填充)之后,初始化回调(如@PostConstruct或InitializingBean)之前。

  • 底层机制:Spring通过BeanPostProcessor(如ApplicationContextAwareProcessor)检测并处理Aware接口,BeanFactory在生成Bean后会判断是否实现了BeanFactoryAware回调对应方法

思考:为什么BeanFactory不识别ApplicationContextAware来回调对应方法呢?而是通过ApplicationContextAwareProcessor来回调?

4.2.2 针对所有bean的扩展点

除了如上闭环在bean本身的扩展点外,还有一种针对所有bean的扩展点,BeanPostProcessor bean的后置处理器

BeanPostProcessor 提供了多个扩展点,允许在Bean的生命周期中插入自定义逻辑。以下是主要扩展点及其作用:


定义Bean初始化前后的处理逻辑(例如总部在咖啡店开店前统一进行培训,开店后输出线上短视频引流)

  • postProcessBeforeInitialization 在Bean的初始化方法(如 @PostConstruct、InitializingBean.afterPropertiesSet())​之前执行。

  • postProcessAfterInitialization(Object bean, String beanName) 在Bean的初始化方法之后执行,常用于生成代理对象(如AOP)。

public class CustomBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("初始化前处理:" + beanName);
        // 
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("初始化后处理:" + beanName);
        return bean;
    }
}

扩展BeanPostProcessor,干预Bean的实例化过程(比如实例化默认的咖啡豆供应商,关系户替换原供应商)

  • postProcessBeforeInstantiation(Class<?> beanClass, String beanName) 在Bean实例化前执行,可返回自定义对象替代原对象(如提前返回代理)。

  • postProcessAfterInstantiation(Object bean, String beanName) 在Bean实例化后、属性注入前执行。

  • postProcessProperties(PropertyValues pvs, Object bean, String beanName) 在属性注入时执行,用于处理 @Autowired注解进行属性注入。

public class CustomInstantiationProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        if (beanClass == UserService.class) {
            // 返回关系户
            return 
        }
        return null; // 默认实例化
    }
}

处理Bean销毁前的逻辑:

  • postProcessBeforeDestruction(Object bean, String beanName) 在Bean销毁前执行(如 @PreDestroy、DisposableBean.destroy() 方法前)。
public class CustomDestructionProcessor implements DestructionAwareBeanPostProcessor {
    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) {
        if (bean instanceof DataSource) {
            ((DataSource) bean).close();
        }
    }
}

处理合并后的Bean定义(Spring中BeanDefinition具备继承体系,甚至可以进行方法充血):

  • postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) 在Bean定义合并后、属性注入前执行,常用于缓存注解元数据(如 @Autowired 标记的字段)。

扩展InstantiationAwareBeanPostProcessor,解决循环依赖和构造函数选择问题

  • determineCandidateConstructors(Class<?> beanClass, String beanName) 确定Bean的构造函数,Spring会反射调用改构造函数进行对象实例化

  • getEarlyBeanReference(Object bean, String beanName) 在Bean未完全初始化时提前暴露引用(解决循环依赖)。

循环依赖会单独章节进行讲解

public class CustomSmartProcessor implements SmartInstantiationAwareBeanPostProcessor {
    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {
        // 选择带有特定注解的构造函数
        return Arrays.stream(beanClass.getConstructors())
            .filter(c -> c.isAnnotationPresent(Autowired.class))
            .toArray(Constructor[]::new);
    }
}

后续单独章节讲解源码,有所认识即可

4.2.3 容器级别的扩展点

在 Spring 框架中,BeanFactoryPostProcessor 允许在容器初始化后、Bean 实例化前修改 Bean 的定义(BeanDefinition)。以下是其核心扩展点及实现类:

作用:修改或覆盖 Bean 的定义(如属性值、作用域等)。

核心方法:void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        BeanDefinition beanDef = beanFactory.getBeanDefinition("userService");
        beanDef.setInitMethod("init"); //设置初始化方法
    }
}

在 BeanFactoryPostProcessor 的基础上,扩展了 动态注册新 Bean 的能力,核心方法

void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

public class CustomRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        // 动态注册新 Bean
        GenericBeanDefinition beanDef = new GenericBeanDefinition();
        beanDef.setBeanClassName("com.example.UserService");
        registry.registerBeanDefinition("userService", beanDef);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 修改现有 Bean 的定义
    }
}

后续单独章节讲解源码,有所认识即可

面试题&知识总结

请详细描述Spring框架Bean的生命周期包括哪些阶段

理解大于记忆:

  1. 要意识到Spring中的bean也是对象:是对象就有实例化,因此Spring在实例化前后可以通过BeanPostProcessor进行扩展。实例化前可以返回对象,阻断BeanFactory创建对象;实例化后可以返回对象替换beanFactory创建的对象(例如:动态代理)
  2. 要意识到对象实例化了不代表可以使用:还需要进行初始化,因此Spring提供了众多的初始化扩展点,例如BeanPostProcessor在初始化前后可以进行扩展,还有可以通过BeanDefinition指定init-method、通过@PostContruct定义初始化方法,还可以实现InitializingBean来自定义初始化方法
  3. 要意识到bean还有销毁阶段:可以通过BeanDefinition指定destory-method、实验@PreDestory、实现DisposableBean
  4. 要理解生命周期扩展点是分层的:
  5. 闭环在bean本身的扩展点:🌰通过BeanDefinition指定init-method、通过@PostContruct定义初始化方法,还可以实现InitializingBean来自定义实例化方法(小陈可以自己定义自己的咖啡店要做哪些前置准备)
  6. 针对所有bean到扩展点:BeanPostProcessor(设备管理中心可以定义每一个咖啡店怎么处理,实例化前后,初始化前后等等)
  7. 针对容器的扩展点:BeanFactoryPostProcessor 可以对BeanDefinition,BeanFactory进行调整(总部可以对设备管理中心进行调整,可以为每一个咖啡店加上序号)
  8. 理解Aware:Aware接口是一组用于让Bean感知容器特定功能的接口。它们允许Bean在初始化阶段获取Spring容器提供的底层资源或上下文信息,从而实现更灵活的交互。

Spring生命周期,是Spring 管理的Bean从无到有的过程。

  1. 首先是BeanDefinition的生成,可以通过注解或者xml生成BeanDefinition,BeanDefinition指导Spring容器管理Bean。随后在Spring容器启动时可以通过BeanFactoryPostProcessor来对BeanFactory做扩展操作,甚至是改变BeanDefinition

  2. Spring中的Bean也是一个个java对象,Spring会通过构造函数或者工厂方法反射生成bean,然后进行属性赋值依赖注入。这个过程可以通过BeanPostProccessor进行干预,在实例化前后进行扩展性操作。

  3. 初始化,Spring会调用Aware接口的方法,@PostConstruct 注解的方法,InitializingBean 接口的 afterPropertiesSet()、自定义 init-method(通过 XML 或 @Bean 指定)的方法,这个过程也可以通过BeanPostProcessor进行干预,在初始化前后进行扩展。

  4. 销毁:对于单例Bean会调用@PreDestroy 注解的方法、DisposableBean 接口的 destroy()。自定义 destroy-method(仅单例 Bean 生效)

  • 痛点:代码重复、容易遗漏步骤(如忘记调用 destroy() 导致资源泄漏)。

  • 痛点:资源获取和释放逻辑分散在业务代码中(使用完DataSource后需要手动调用close方法进行资源释放),难以维护。

>>>点击去看配套视频<<<