全网最详细的Spring bean生命周期详解

Spring Bean 生命周期详解(超详细版)

目标:把 Bean 从“出生”到“死亡” 的全过程讲清楚,并把你能“插手改命”的关键扩展点都标出来。


1. 一句话总览

Spring Bean 的生命周期可以粗略理解成:

  1. 扫描/注册 BeanDefinition(只是“户口本”,不是对象)
  2. 实例化(new / 反射 / 工厂方法)
  3. 属性填充(依赖注入、@Autowired 等)
  4. 各种 Aware 回调(给你“上下文信息”)
  5. BeanPostProcessor 前置处理(初始化前拦一下)
  6. 初始化(@PostConstruct / InitializingBean / init-method)
  7. BeanPostProcessor 后置处理(初始化后拦一下,常用来创建 AOP 代理)
  8. 就绪可用
  9. 销毁(@PreDestroy / DisposableBean / destroy-method)

2. 先搞清楚:BeanDefinition vs Bean

BeanDefinition:描述 Bean 的“配方/元数据”,比如:

  • class 是谁
  • scope(singleton/prototype/…)
  • 构造参数、属性值
  • init-method / destroy-method
  • 是否 lazy
  • 是否 primary
  • 依赖关系 depends-on 等

Bean:真正创建出来的 Java 对象。

很多“容器启动很快但第一次调用慢”的原因,就是前面只注册了 BeanDefinition,没有真正实例化(lazy 或者还没触发 getBean)。


3. 最经典的生命周期流程(以 singleton 为主)

下面按 Spring 容器 refresh 后的创建过程讲(最常见):

3.1 Bean 创建主流程(按时间顺序)

  1. 解析配置并注册 BeanDefinition

    • XML / Java Config / @ComponentScan / ImportSelector / Registrar
    • 典型扩展点:BeanFactoryPostProcessor / BeanDefinitionRegistryPostProcessor
  2. 实例化 Instantiation

    • 选择构造器:无参 / 有参(构造器注入)
    • 也可能走 工厂方法@BeanFactoryBeanSupplier
    • 典型扩展点:
      • InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
      • SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
  3. 设置属性 Populate Properties(依赖注入)

    • 字段注入、setter 注入、@Autowired/@Resource、@Value 等
    • 典型扩展点:
      • InstantiationAwareBeanPostProcessor#postProcessProperties
      • AutowiredAnnotationBeanPostProcessor 就在这里干活
  4. Aware 回调(容器把“环境信息”塞给你)
    常见顺序大致为:

    • BeanNameAware#setBeanName
    • BeanClassLoaderAware#setBeanClassLoader
    • BeanFactoryAware#setBeanFactory
    • (在 ApplicationContext 场景下)ApplicationContextAware#setApplicationContext
    • 还有:EnvironmentAwareResourceLoaderAwareApplicationEventPublisherAware
  5. BeanPostProcessor:初始化前

    • BeanPostProcessor#postProcessBeforeInitialization
    • 常见用途:做一些初始化前的增强、字段处理、校验等
  6. 初始化 Initialization(三种方式都可能存在)
    按“常见执行顺序”列一下(实际会受实现细节影响,但你可以这样记):

    • @PostConstruct(JSR-250)
    • InitializingBean#afterPropertiesSet
    • init-method(XML 或 @Bean(initMethod=“…”))
  7. BeanPostProcessor:初始化后(非常关键)

    • BeanPostProcessor#postProcessAfterInitialization
    • AOP 代理(如 AbstractAutoProxyCreator)通常在这里把原对象“替换成代理对象”
    • 这就是为什么你注入进来的对象可能不是原类,而是代理
  8. 单例池缓存 & 对外可用

    • singleton 会放入缓存(singletonObjects)
    • 之后 getBean 基本就是从缓存取
  9. 销毁 Destroy(容器关闭时触发)
    对 singleton 才有完整销毁回调;prototype 默认不由容器托管销毁(见后文)。

    常见销毁顺序(记住:也是“三种方式”):

    • @PreDestroy
    • DisposableBean#destroy
    • destroy-method

4. 用一张“顺序图”记住关键节点

BeanDefinition 已注册
        |
        v
[实例化] -> new / 构造器 / 工厂方法 / Supplier
        |
        v
[属性填充] -> DI / @Autowired / @Value
        |
        v
[Aware 回调] -> BeanNameAware/BeanFactoryAware/ApplicationContextAware...
        |
        v
[BPP BeforeInit] -> postProcessBeforeInitialization
        |
        v
[初始化] -> @PostConstruct -> afterPropertiesSet -> init-method
        |
        v
[BPP AfterInit] -> postProcessAfterInitialization (AOP代理常在这)
        |
        v
Bean 可用
        |
        v
容器关闭
        |
        v
[销毁] -> @PreDestroy -> destroy -> destroy-method

5. 你能“插手”的扩展点(超级重要)

5.1 BeanFactoryPostProcessor(创建 Bean 之前改“配方”)

  • 作用:修改 BeanDefinition(还没实例化对象)
  • 典型实现:PropertySourcesPlaceholderConfigurer、自定义占位符处理等
@Component
public class MyBFPP implements BeanFactoryPostProcessor {
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
    // 可以修改 BeanDefinition,例如改 scope、改属性值等
  }
}

记忆法:BFPP = Before Factory creates Beans(在工厂真正造对象前动手)。


5.2 BeanPostProcessor(创建 Bean 过程中改“对象”)

  • 作用:对象级别增强(初始化前后)
  • 典型实现:AutowiredAnnotationBeanPostProcessor、AOP 的自动代理创建器
@Component
public class MyBPP implements BeanPostProcessor {
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) {
    return bean;
  }
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) {
    return bean;
  }
}

记忆法:BPP = Bean 的“出厂质检+改装”流程


5.3 InstantiationAwareBeanPostProcessor(更早、甚至能“拦截实例化”)

  • 可以在实例化前返回代理对象,直接跳过默认实例化过程
  • 常用于某些框架的高级注入、代理生成

6. 初始化与销毁:到底谁先谁后?

6.1 初始化(通常你关心的)

常见执行链路(便于记忆):

  1. @PostConstruct
  2. afterPropertiesSet
  3. init-method
  4. postProcessAfterInitialization(可能返回代理)

注意:

  • @PostConstruct 要求对应的 BPP 生效(通常是 CommonAnnotationBeanPostProcessor)。
  • 如果你发现 @PostConstruct 不执行,先怀疑:容器环境/依赖是否启用、Bean 是否真的被创建。

6.2 销毁

  1. @PreDestroy
  2. DisposableBean#destroy
  3. destroy-method

7. 不同 scope 的差异(很容易踩坑)

7.1 singleton(默认)

  • 容器启动/首次使用时创建(取决于 lazy)
  • 容器关闭时会走完整销毁流程

7.2 prototype(每次 getBean 都 new 一个)

  • 容器只负责“创建 + 初始化”
  • 默认不负责销毁(不会自动调用 @PreDestroy / destroy-method)
  • 如果你创建了 prototype 并且持有外部资源(线程池/连接),你要自己负责释放

7.3 request / session / application(Web 场景)

  • 生命周期和 HTTP 请求、会话绑定
  • 销毁由 Web 容器/上下文驱动

8. Bean 的“三级缓存”与循环依赖(面试+实战都爱问)

8.1 为什么会有三级缓存?

为了处理 singleton 的循环依赖(A 依赖 B,B 又依赖 A),Spring 引入:

  • 一级缓存:singletonObjects(成熟成品)
  • 二级缓存:earlySingletonObjects(早期引用)
  • 三级缓存:singletonFactories(ObjectFactory,用来生成早期引用/代理)

核心思路:

  • 先把“能返回早期引用的工厂”放进三级缓存
  • 需要时提前暴露一个早期对象引用解决循环依赖
  • 之后对象初始化完成,再放到一级缓存

8.2 哪些循环依赖能解决?

  • singleton + setter/字段注入:通常可解
  • 构造器注入形成循环依赖:通常不可解(因为实例都造不出来)
  • prototype 循环依赖:通常不可解(每次都新建,没法缓存)

9. FactoryBean:别把它当普通 Bean

  • 普通 Bean:getBean("userService") 返回 userService 实例
  • FactoryBeangetBean("xxxFactoryBean") 默认返回 它生产的对象
  • 想拿到 FactoryBean 自己:getBean("&xxxFactoryBean")

用途:复杂对象创建(例如 MyBatis 的 MapperFactoryBean)。


10. ApplicationContext 多出来的“容器事件阶段”

如果你用的是 ApplicationContext(大部分 Spring Boot / Spring 项目都是):

  • ContextRefreshedEvent:容器 refresh 完成
  • ContextClosedEvent:容器关闭

你还会见到:

  • ApplicationRunner / CommandLineRunner(Spring Boot 启动后执行)
  • SmartLifecycle(更精细控制启动/停止阶段)

这些属于“容器生命周期”,不完全等于单个 Bean 的生命周期,但经常一起被问。


11. 一个最小可运行示例:观察完整顺序

@Component
public class LifeDemo implements BeanNameAware, BeanFactoryAware,
        InitializingBean, DisposableBean {

    public LifeDemo() {
        System.out.println("1) 构造方法");
    }

    @Autowired
    public void setXxx(SomeDep dep) {
        System.out.println("2) 属性注入/依赖注入");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("3) BeanNameAware: " + name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        System.out.println("4) BeanFactoryAware");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("5) @PostConstruct");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("6) InitializingBean.afterPropertiesSet");
    }

    public void initMethod() {
        System.out.println("7) init-method");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("8) @PreDestroy");
    }

    @Override
    public void destroy() {
        System.out.println("9) DisposableBean.destroy");
    }

    public void destroyMethod() {
        System.out.println("10) destroy-method");
    }
}

如果你用 @Bean 注册它:

@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public LifeDemo lifeDemo() {
    return new LifeDemo();
}

12. 常见坑点(踩过一次就记住)

  1. @PostConstruct 不执行

    • Bean 没有真正创建(lazy 或从未被引用)
    • 对应的处理器没生效(环境/依赖/配置)
    • Bean 被代理替换导致你观察对象不对(但方法仍会在目标对象上执行)
  2. prototype 资源泄漏

    • prototype 不自动销毁,你必须手动释放
  3. AOP 代理导致 this 调用失效

    • 在同一个类里 this.xxx() 不会走代理,事务/切面可能不生效
    • 解决:拆分类、通过注入自身代理、或用 AopContext(不推荐滥用)
  4. 构造器循环依赖

    • 改为 setter/字段注入,或者重构依赖关系

13. 速记卡(面试一分钟版本)

  • BeanDefinition 先注册,Bean 后创建
  • 创建顺序:实例化 → 属性填充 → Aware → BPP BeforeInit → 初始化(@PostConstruct / afterPropertiesSet / init-method) → BPP AfterInit(AOP代理) → 可用
  • 销毁顺序:@PreDestroy → DisposableBean.destroy → destroy-method
  • prototype 不托管销毁
  • 循环依赖:singleton setter 通常可解,构造器/ prototype 通常不可解
  • AOP 通常在 postProcessAfterInitialization 生成代理

14. 你可以怎么用它(实战建议)

  • 需要“依赖注入完成后初始化”:优先用 @PostConstruct
  • 需要“对外部资源做关闭”:singleton 用 @PreDestroy;prototype 自己管理
  • 需要“改 Bean 配方/批量改属性”:用 BeanFactoryPostProcessor
  • 需要“统一做对象增强/代理”:用 BeanPostProcessor

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值