Spring Bean生命周期- BeanDefinition 加载与 BeanFactoryPostProcessor BeanPostProcessor

使用细节

  1. 默认是单例singleton,在启动容器时,默认就会创建,并放入到singletonObjects集合中存储实例
  2. 当 设置为多实例机制后,该bean是在getBean()时才创建
  3. 如果是单例singleton,同时希望在getBean时才创建,可以 指定懒加载 lazy-init="true" (注意默认是false)
  4. 通常情况下, lazy-init 就使用默认值false ,在开发看来,用空间换时间是值得的,除非有特殊的要求.
  5. 如果scope="prototype" 这时你的 lazy-init 属性的值不管是 true,还是false 都是在getBean时候,才创建对象.

BeanDefinition 与 singletonObjects 的区别

BeanDefinition

  • 存储内容 : 存储 bean 的元数据信息(配置信息)
  • 包含内容: bean 的类名、作用域(scope)、属性值、依赖关系、初始化方法、销毁方法等
  • 创建时机: Spring 容器启动时,解析 XML/注解配置后创建
  • 存储位置: 保存在 BeanFactory/ApplicationContext 中,作为创建 bean 实例的模板

singletonObjects

  • 存储内容 : 存储单例 bean 的实际实例对象
  • 包含内容: 已经完成实例化、属性注入、初始化的 bean 对象
  • 创建时机: 单例 bean 实例化后(默认启动时,懒加载则第一次 getBean 时)
  • 存储位置: 作为单例缓存,避免重复创建相同实例
  • 非单例 bean 的处理 : 非单例 bean(如 prototype 作用域)不会被放入 singletonObjects

不同作用域的 bean 存储方式

  1. singleton(单例) : 实例放入 singletonObjects 缓存,重复使用
  2. prototype(原型/多实例) : 每次调用 getBean() 都创建新实例,不缓存,使用后由调用者负责销毁
  3. request(请求): 每个 HTTP 请求创建新实例,请求结束后销毁(仅 Web 环境)
  4. session(会话): 每个 HTTP 会话创建新实例,会话结束后销毁(仅 Web 环境)
  5. application(应用): 每个 ServletContext 创建新实例,应用停止后销毁(仅 Web 环境)

结论 : 只有 singleton 作用域的 bean 会被放入 singletonObjects 集合,其他作用域的 bean 不会被缓存。

Bean 的生命周期

生命周期概述

Spring Bean 的生命周期是指从 Bean 被创建、初始化、使用到最终销毁的完整过程。Spring 容器负责管理 Bean 的整个生命周期,确保 Bean 在合适的时机完成相应的操作。

详细阶段说明

  1. 根据 xml 配置文件或注解配置, Spring 容器会解析 Bean 定义,并创建一个 BeanDefinition 对象, 该对象包含了 Bean 的元数据信息(类名,作用域,属性值,依赖关系等)
  2. 执行 BeanFactoryPostProcessor : 在所有 BeanDefinition 加载完成后,Bean 实例化之前,Spring 容器会调用所有实现了 BeanFactoryPostProcessor 接口的类的 postProcessBeanFactory 方法。这些方法可以修改 BeanDefinition 的元数据信息(如属性值、作用域等)
  3. 通过反射机制,根据 BeanDefinition 中的类名,调用对应的构造函数,创建 Bean 的实例.
  4. 属性注入 (DI) : Spring 容器会根据 BeanDefinition 中的依赖关系,将对应的 Bean 实例注入到目标 Bean 的属性中.
  5. 初始化 : 调用 Bean 的初始化方法(如实现 InitializingBean 接口的 afterPropertiesSet 方法,或指定的 init-method 方法)
  6. 通过getBean()方法获取Bean实例时,Spring容器会返回该Bean的实例.
  7. 销毁 : 当 Bean 实例不再需要时,Spring 容器会调用 Bean 的销毁方法(如实现 DisposableBean 接口的 destroy 方法,或指定的 destroy-method 方法)
1. BeanDefinition 加载与 BeanFactoryPostProcessor 执行
  • 时机: Spring 容器启动时,所有 BeanDefinition 加载完成后,Bean 实例化之前
  • 操作 :
    • Spring 容器解析 XML/注解配置,创建所有 BeanDefinition 对象
    • 调用所有实现了 BeanFactoryPostProcessor 接口的类的 postProcessBeanFactory 方法
  • 作用 :
    • 可以修改 BeanDefinition 的元数据信息(如属性值、作用域、初始化方法等)
    • 典型应用:PropertyPlaceholderConfigurer(处理 ${} 占位符)、CustomScopeConfigurer(注册自定义作用域)
  • 执行特点: 在所有 Bean 实例化之前执行,且只执行一次
2. 实例化(Instantiation)
  • 时机: Spring 容器根据 BeanDefinition 创建 Bean 实例
  • 操作: 调用 Bean 的构造函数创建对象
  • 结果: 获得一个原始的 Bean 实例(尚未设置任何属性)
3. 属性注入(Populate)
  • 时机: 实例化完成后
  • 操作: 根据配置(XML/注解)将依赖注入到 Bean 的属性中
  • 实现: 调用 setter 方法或通过构造函数注入依赖
  • 这里的"bean"指 : 刚刚完成实例化阶段(通过构造函数创建)的原始 Bean 实例。此时它已经是一个 Java 对象,但尚未设置任何属性值,处于"原始状态"。Spring 容器会将配置中定义的属性值、依赖对象等注入到这个原始实例中,使其成为一个完整可用的 Bean。

例如:当实例化 User 类获得一个 user 对象后,此时 user.name 可能为 null(默认值),属性注入阶段会将配置的 name 值注入到 user 对象中。

4. 初始化前(Before Initialization)
  • 时机: 属性注入完成后
  • 操作 : 调用 BeanPostProcessor 的 postProcessBeforeInitialization 方法
  • 作用: 可以在 Bean 初始化前对其进行增强处理
5. 初始化(Initialization)
  • 时机: 初始化前阶段完成后
  • 操作: 执行自定义的初始化逻辑
  • 实现方式 :
    • 实现 InitializingBean 接口的 afterPropertiesSet() 方法
    • 在配置中指定 init-method 属性
    • 使用 @PostConstruct 注解标记初始化方法
6. 初始化后(After Initialization)
  • 时机: 初始化完成后
  • 操作 : 调用 BeanPostProcessor 的 postProcessAfterInitialization 方法
  • 作用: 可以在 Bean 初始化后进行代理创建或其他增强处理
7. 加入 IoC 容器(Add to IoC Container)
  • 时机: 初始化后阶段完成后(仅针对 singleton 作用域)
  • 操作 : Spring 容器将完全初始化的单例 Bean 放入 singletonObjects 缓存中
  • 作用 : 后续调用 getBean() 时直接从缓存返回,避免重复创建
  • 非单例 Bean 的处理 : prototype、request、session、application 等作用域的 Bean 不会被加入 singletonObjects 缓存
8. 使用阶段(In Use)
  • 时机: Bean 完全初始化后(单例 Bean 已加入容器缓存)
  • 操作 : Bean 可以被应用程序使用(通过 getBean() 获取)
  • 特点 :
    • 单例 Bean:从 singletonObjects 缓存获取,重复使用
    • 原型 Bean:每次调用 getBean() 都创建新实例,使用后由调用者负责管理
    • 其他作用域:根据各自作用域规则创建和管理
9. 销毁前(Before Destruction)
  • 时机: 容器关闭前(仅单例 Bean)
  • 操作: 执行自定义的销毁逻辑
  • 实现方式 :
    • 实现 DisposableBean 接口的 destroy() 方法
    • 在配置中指定 destroy-method 属性
    • 使用 @PreDestroy 注解标记销毁方法
10. 销毁(Destruction)
  • 时机: 销毁前阶段完成后
  • 操作: 释放 Bean 占用的资源
  • 注意: 仅单例 Bean 会被容器管理销毁,原型 Bean 由调用者负责销毁

生命周期回调方法示例

java 复制代码
public class User {
    private String name;
    
    // 构造函数(实例化阶段调用)
    public User() {
        System.out.println("1. User 构造函数被调用(实例化)");
    }
    
    // setter 方法(属性注入阶段调用)
    public void setName(String name) {
        this.name = name;
        System.out.println("2. setName 被调用(属性注入)");
    }
    
    // InitializingBean 接口方法(初始化阶段调用)
    @Override
    public void afterPropertiesSet() {
        System.out.println("3. afterPropertiesSet 被调用(InitializingBean 接口)");
    }
    
    // 自定义初始化方法(配置 init-method 指定)
    public void init() {
        System.out.println("4. init 方法被调用(自定义初始化)");
    }
    
    // 业务方法(使用阶段调用)
    public void sayHello() {
        System.out.println("5. sayHello 方法被调用(使用中)");
    }
    
    // DisposableBean 接口方法(销毁阶段调用)
    @Override
    public void destroy() {
        System.out.println("6. destroy 方法被调用(DisposableBean 接口)");
    }
    
    // 自定义销毁方法(配置 destroy-method 指定)
    public void cleanup() {
        System.out.println("7. cleanup 方法被调用(自定义销毁)");
    }
}

不同作用域对生命周期的影响

作用域 实例化时机 初始化时机 销毁时机 容器管理销毁
singleton 容器启动(默认)/第一次 getBean 实例化后立即初始化 容器关闭前
prototype 每次 getBean 实例化后立即初始化 调用者负责销毁
request 每个 HTTP 请求开始 实例化后立即初始化 HTTP 请求结束 是(Web环境)
session 每个 HTTP 会话开始 实例化后立即初始化 HTTP 会话结束 是(Web环境)
application 应用启动 实例化后立即初始化 应用停止 是(Web环境)

关系说明

  1. Spring 先读取配置创建 BeanDefinition(元数据)
  2. 然后根据 BeanDefinition 的配置创建实际的 bean 实例
  3. 单例实例创建完成后,会被放入 singletonObjects 缓存中
  4. 后续调用 getBean() 获取单例时,直接从缓存返回,不再重新创建

因此,"存储到实体类中 BeanDefinition" 和 "放入到 singletonObjects 集合" 描述的是 Spring 管理 bean 的不同阶段

  • BeanDefinition 是配置模板
  • singletonObjects 是实例缓存
    两者都是正确的,只是描述了 bean 生命周期中的不同环节。
相关推荐
222you2 小时前
Java线程的三种创建方式
java·开发语言
脸大是真的好~2 小时前
计算机408基础相关面试题-备用,不推荐
java
云上漫步者2 小时前
深度实战:Rust交叉编译适配OpenHarmony PC——unicode_width完整适配案例
开发语言·后端·rust·harmonyos
小费的部落2 小时前
Excel 在Sheet3中 匹配Sheet1的A列和Sheet2的A列并处理空内容
java·前端·excel
咘噜biu2 小时前
多租户动态数据源插件dynamic-datasource简介
java·mybatisplus·动态数据源·多租户
漫漫求2 小时前
Java内存模型【JMM】、JVM内存模型
java·开发语言·jvm
原来是好奇心2 小时前
深入Spring Boot源码(五):外部化配置与Profile机制深度解析
java·源码·springboot
IT界的奇葩2 小时前
OAuth2 单点登录流程图
java·流程图·oauth2·单点登录·sso
Java水解2 小时前
MySQL必备基础
后端·mysql