当前位置: 首页 > news >正文

Spring Bean生命周期全解析:从创建到销毁的底层细节

一、Bean生命周期全景概览

Spring框架的核心是IoC(控制反转)容器,它负责管理应用中所有Bean的完整生命周期。理解Bean生命周期不仅是掌握Spring框架的基础,更是排查复杂问题、进行高级定制开发的关键。一个Bean从定义到销毁的完整生命周期包含以下阶段:

值得注意的是,单例Bean(Singleton) 和原型Bean(Prototype) 的生命周期管理存在显著差异:

  • 单例Bean:容器启动时创建,与容器生命周期一致,容器关闭时销毁

  • 原型Bean:每次请求时创建,容器不管理其销毁,由垃圾回收器回收

生命周期阶段单例Bean原型Bean
创建时机容器启动时每次getBean()时
存储位置单例池缓存不缓存,每次新建
销毁管理容器关闭时销毁不管理,依赖GC

二、Bean生命周期的底层细节剖析

1. Bean定义加载与解析

Spring容器启动时,会扫描所有配置源(XML、注解、Java配置),将Bean的定义信息解析为BeanDefinition对象,这是Spring内部描述Bean的元数据结构。关键步骤包括:

  • 配置解析:读取@Component@Bean等配置信息

  • BeanDefinition创建:生成包含类名、作用域、延迟加载等属性的BeanDefinition

  • 注册到容器:通过BeanDefinitionRegistry将BeanDefinition注册到容器

// 示例:BeanDefinition的关键属性
public class RootBeanDefinition {private volatile Object beanClass;private String scope = BeanDefinition.SCOPE_SINGLETON;private boolean lazyInit = false;private ConstructorArgumentValues constructorArgumentValues;private MutablePropertyValues propertyValues;// ...
}

2. Bean实例化:从无到有的诞生

实例化是创建Bean对象的第一步,Spring通过反射机制调用构造方法完成对象创建,这一步涉及核心流程:

  • 构造方法推断

    • 若有唯一构造方法,直接使用

    • 若有多个构造方法,优先选择带@Autowired注解的

    • @Autowired时选择无参构造,若无则报错

  • 实例化策略

    • 普通构造Class.newInstance()

    • 工厂方法:静态工厂或实例工厂方式创建

  • 提前暴露引用:为解决循环依赖,Spring在实例化后立即将原始对象包装成ObjectFactory放入三级缓存singletonFactories

3. 属性填充:依赖注入的底层实现

属性填充阶段是Spring实现依赖注入(DI) 的核心,主要涉及三种注入方式:

  1. 字段注入:通过反射直接设置字段值(需@Autowired

  2. Setter注入:调用Setter方法注入

  3. 构造器注入:实例化时通过构造参数注入(推荐首选)

// 构造器注入示例(推荐方式)
@Component
public class OrderService {private final PaymentService paymentService;@Autowired // Spring 4.3+可省略public OrderService(PaymentService paymentService) {this.paymentService = paymentService;}
}

循环依赖解决机制是此阶段最复杂的部分,Spring通过三级缓存解决:

  1. 一级缓存singletonObjects - 存放完全初始化好的Bean

  2. 二级缓存earlySingletonObjects - 存放早期暴露的Bean(已实例化但未初始化)

  3. 三级缓存singletonFactories - 存放Bean工厂,用于生成早期引用

当Bean A依赖Bean B时:

  1. A实例化后将自己放入三级缓存

  2. A在填充属性时发现需要B,触发B的创建

  3. B实例化后将自己放入三级缓存

  4. B填充属性时需要A,从三级缓存获取A的早期引用

  5. B完成初始化移入一级缓存

  6. A获取B的完成实例,继续初始化

4. Aware接口回调:获取容器基础设施

在属性注入后,Spring会检查Bean是否实现了特定的Aware接口,并通过回调方法注入容器基础设施:

  • BeanNameAware:设置Bean的ID

  • BeanFactoryAware:设置BeanFactory引用

  • ApplicationContextAware:设置ApplicationContext引用(最常用)

@Component
public class SystemMonitor implements ApplicationContextAware {private ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext ctx) {this.context = ctx; // 获得ApplicationContext引用}
}

5. 初始化阶段:BeanPostProcessor的魔法

初始化是Bean生命周期的关键阶段,BeanPostProcessor在此发挥核心作用:

5.1 初始化前处理

调用所有BeanPostProcessor.postProcessBeforeInitialization()方法,这是AOP代理等高级特性的入口点

5.2 初始化方法执行

Spring按固定顺序执行三种初始化方法:

  1. @PostConstruct注解方法:JSR-250标准

  2. InitializingBean.afterPropertiesSet():Spring接口实现

  3. 自定义init-method:通过XML或@Bean(initMethod="...")指定

@Component
public class DatabaseInitializer {@PostConstructpublic void postConstruct() {System.out.println("@PostConstruct方法执行");}@Override // 实现InitializingBeanpublic void afterPropertiesSet() {System.out.println("afterPropertiesSet执行");}public void customInit() {System.out.println("自定义init-method执行");}
}
5.3 初始化后处理

调用BeanPostProcessor.postProcessAfterInitialization()方法,此处会完成AOP代理对象的生成

  • 若Bean需要代理,返回代理对象

  • 否则返回原始对象

6. Bean就绪与使用

完成所有初始化步骤后,Bean会被放入单例池(singletonObjects),处于就绪状态,可被应用程序使用。此时Bean包含所有依赖且已完成自定义初始化逻辑。

对于原型作用域(Prototype) 的Bean:

  • 每次getBean()时都会触发完整生命周期

  • 容器不管理原型Bean的销毁

7. 销毁阶段:优雅释放资源

当容器关闭(调用close())时,单例Bean进入销毁阶段,执行顺序为:

  1. @PreDestroy注解方法:JSR-250标准

  2. DisposableBean.destroy():Spring接口实现

  3. 自定义destroy-method:通过XML或@Bean(destroyMethod="...")指定

@Component
public class ResourceCleanup implements DisposableBean {@PreDestroypublic void preDestroy() {System.out.println("@PreDestroy方法执行");}@Overridepublic void destroy() {System.out.println("DisposableBean.destroy()执行");}public void customDestroy() {System.out.println("自定义destroy-method执行");}
}

三、高级主题与最佳实践

1. 循环依赖的深度解析

Spring只能解决单例作用域且通过Setter/字段注入的循环依赖。构造器注入的循环依赖无法解决,因为实例化时需要完整依赖。解决方案:

  1. 使用Setter/字段注入替代构造器注入

  2. 使用@Lazy延迟加载依赖

  3. 重构代码消除循环依赖

2. 生命周期扩展点实战

2.1 自定义BeanPostProcessor

可拦截所有Bean的创建过程:

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

在所有单例Bean初始化完成后执行:

@Component
public class CacheWarmer implements SmartInitializingSingleton {@Overridepublic void afterSingletonsInstantiated() {// 预热缓存等操作}
}

3. 最佳实践总结

  1. 注入方式选择

    • 强制依赖使用构造器注入

    • 可选依赖使用Setter注入

    • 避免使用字段注入(不利于测试)

  2. 初始化逻辑

    • 优先使用@PostConstruct而非InitializingBean(减少框架耦合)

    • 耗时操作避免放在初始化方法中(影响启动速度)

  3. 作用域选择

    • 无状态服务使用Singleton

    • 有状态对象使用Prototype

  4. 循环依赖预防

    • 保持依赖树单向

    • 使用事件机制解耦

    • 必要时使用@Lazy

四、常见问题排查指南

问题现象可能原因解决方案
Bean创建时NPE依赖未完全注入检查依赖是否全部声明
使用构造器注入保证完全初始化
循环依赖报错构造器注入的循环依赖改为Setter注入
使用@Lazy延迟加载
@PostConstruct未执行Bean未被容器管理
配置扫描路径错误
检查@Component注解
确认@ComponentScan配置
代理对象方法不生效自调用绕过代理
AOP切面配置错误
通过容器获取Bean
检查@Aspect配置
销毁方法未执行原型作用域Bean
未调用context.close()
单例Bean才有销毁
显式关闭ApplicationContext

相关文章:

  • Docker MCP 目录和工具包简介:使用 MCP 为 AI 代理提供支持的简单安全方法
  • Flask+LayUI开发手记(八):通用封面缩略图上传实现
  • 复变函数中的对数函数及其MATLAB演示
  • 深入理解React Hooks的原理与实践
  • RDMA简介5之RoCE v2队列
  • 【高等数学】傅里叶级数逼近例子
  • 将 Jupyter Notebook 的默认存储路径从 C 盘迁移到 D 盘,可以通过以下步骤实现:
  • [密码学实战]彻底理解位(bit)与字节(byte)在十六进制处理中的区别
  • 【EN 18031】访问控制机制(ACM - 3):儿童玩具的防护盾
  • vue:当前对象添加对应值
  • Python cryptography【密码库】库功能与使用指南
  • 【Redis】类型补充
  • 墨者学院-密码学实训隐写术第二题
  • [闭源saas选项]Pinecone:为向量数据库而生的实时语义搜索引擎
  • 【网络安全】XSS攻击
  • Spring AI(10)——STUDIO传输的MCP服务端
  • MyBatis-Plus深度全解:从入门到企业级实战
  • idea json生成实体类
  • 【Git系列】如何同步原始仓库的更新到你的fork仓库?
  • Spring之事务管理方式
  • 我想做个网站/电商代运营公司100强
  • 特克斯与凯科斯群岛域名官方网站/近期舆情热点事件
  • wordpress可视化函数/深圳seo博客
  • 如何用eclipse做网站/百度搜索网站优化
  • 广州网站优化注意事项/网络推广工作
  • 金融网站建设/sem营销