首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >手撕Spring底层系列之:Bean的生命周期

手撕Spring底层系列之:Bean的生命周期

作者头像
Xxtaoaooo
发布2025-10-13 15:28:34
发布2025-10-13 15:28:34
3760
举报
文章被收录于专栏:Debug日志Debug日志

人们眼中的天才之所以卓越非凡,并非天资超人一等而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成超凡的必要条件。———— 马尔科姆·格拉德威尔

🌟 嗨,我是Xxtaoaooo!

本系列将用源码解剖+拆分核心轮子的方式,带你暴力破解Spring底层逻辑。 警告:阅读后可能导致看Spring源码时产生「庖丁解牛」般的快感! 话不多说,直接开干!

一、Bean生命周期全景

💡 灵魂一问:当你使用@Autowired注入一个Bean时,是否思考过它如何跨越“实例化-注入-代理”的九重关卡,最终成为你手中可用的对象?

Spring Bean生命周期囊括6大阶段与14个关键节点;从 Bean 实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。

1.1 核心流程图(建议收藏)


二、深度拆解:6大阶段源码级剖析

2.1 实例化(Instantiation)—— 生命的起点

触发时机:容器解析BeanDefinition后,调用createBeanInstance() 底层机制

代码语言:javascript
复制
// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 1. 解析构造函数
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
        // 使用AutowiredAnnotationBeanPostProcessor推断构造器
        return autowireConstructor(beanName, mbd, ctors, args);
    }
    // 2. 无特殊构造器则调用instantiateBean() -> 反射调用默认构造器
    return instantiateBean(beanName, mbd);
}

关键扩展点

  • InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()若返回非null对象,则直接跳过后续实例化流程(AOP代理的入口)。

2.2 属性填充(Population)—— 依赖注入的本质

依赖注入三种方式

注入方式

实现类

应用场景

字段注入(Field)

AutowiredAnnotationBeanPostProcessor

@Autowired 、@Value

Setter注入

CommonAnnotationBeanPostProcessor

@Resource

构造器注入

ConstructorResolver

循环依赖安全方案

源码截取

代码语言:javascript
复制
// AbstractAutowireCapableBeanFactory.populateBean()
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // 执行InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                // 控制是否继续属性填充
                if (!((InstantiationAwareBeanPostProcessor) bp).postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    return;
                }
            }
        }
    }
    // 依赖注入核心逻辑(如@Autowired)
    applyPropertyValues(beanName, mbd, bw, pvs);
}

2.3 Aware接口回调—— 获取容器“内幕”

三类核心Aware接口

  1. BeanNameAware:注入当前Bean的ID
  2. BeanFactoryAware:注入BeanFactory(谨慎使用,破坏控制反转)
  3. ApplicationContextAware:注入容器本身(可获取环境变量、事件发布等)

⚠️ 警告:过度使用Aware接口会导致代码与Spring强耦合,优先使用依赖注入

2.4 初始化(Initialization)—— 三种方式与执行顺序

初始化方法执行顺序

  1. @PostConstruct注解方法(JSR-250标准
  2. InitializingBean.afterPropertiesSet()(Spring原生接口)
  3. XML或@Bean指定的init-method

源码验证顺序

代码语言:javascript
复制
// InitDestroyAnnotationBeanPostProcessor(处理@PostConstruct)
public Object postProcessBeforeInitialization(Object bean, String beanName) {
    // 执行@PostConstruct方法
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    metadata.invokeInitMethods(bean, beanName);
    return bean;
}

// afterPropertiesSet()在invokeInitMethods()中通过反射调用

2.5 BeanPostProcessor后置处理——AOP的诞生地

核心方法postProcessAfterInitialization() 返回的对象可能已被代理替换

代码语言:javascript
复制
// AbstractAutoProxyCreator.java
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 检查是否需要代理(如存在@Transactional注解)
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey); // 生成代理对象
        }
    }
    return bean;
}

2.6 销毁(Destruction)—— 优雅关闭资源

销毁顺序

  1. @PreDestroy → 2. DisposableBean.destroy() → 3. destroy-method

原型Bean的陷阱:

代码语言:javascript
复制
// 手动销毁原型Bean示例
ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) applicationContext;
beanFactory.destroyScopedBean("prototypeBeanName");

💡 最佳实践:数据库连接池、线程池等资源清理必须放在@PreDestroy中!


三、扩展点全景:5类扩展接口详解

3.1 扩展接口阶段应用

扩展点类型

接口/注解

作用阶段

典型应用

Bean级感知

BeanNameAware 等

属性注入后

获取Bean ID或容器引用

初始化回调

@PostConstruct /InitializingBean

初始化阶段

资源加载、数据预热

后处理器(容器级)

BeanPostProcessor

初始化前后

AOP代理、属性增强

销毁回调

@PreDestroy /DisposableBean

容器关闭时

资源释放、连接关闭

工厂后处理器

BeanFactoryPostProcessor

Bean定义加载后

修改BeanDefinition(如占位符替换)


四、作用域对生命周期的影响

4.1 单例(Singleton) vs 原型(Prototype)

生命周期阶段

单例Bean

原型Bean

实例化时机

容器启动时创建

每次getBean()时创建

初始化完成时机

容器启动时完成

每次注入时完成

销毁时机

容器关闭时统一销毁

容器不管理销毁

4.2 Web作用域的特殊性

  • Request:每次HTTP请求创建新Bean,请求结束销毁
  • Session:每个用户会话创建Bean,会话超时销毁

需配合RequestContextListenerDispatcherServlet使用。


五、企业级避坑指南

5.1 高频问题与解决方案

问题现象

根因分析

解决方案

@PostConstruct 不执行

未扫描到Bean或循环依赖

检查包扫描路径,避免构造器循环依赖

AOP代理失效

内部方法调用未经过代理对象

通过AopContext.currentProxy() 获取代理

原型Bean资源泄漏

容器不销毁原型Bean

手动调用destroy() 或使用@Scope(proxyMode)

BeanFactoryPostProcessor 未生效

过早加载Bean导致后处理器错过时机

确保后处理器在Bean加载前注册

5.2 性能优化关键点

  1. 延迟初始化
代码语言:javascript
复制
@Lazy // 延迟加载直到首次使用
@Service
public class HeavyResourceService { ... }
  1. 精确后处理器过滤:避免无差别扫描所有Bean
代码语言:javascript
复制
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    // 只处理Service层Bean
    if (bean.getClass().isAnnotationPresent(Service.class)) {
        return wrapWithProxy(bean);
    }
    return bean;
}

六、总结

“不理解生命周期的Spring开发者,如同蒙眼行走的旅人。”

当我第一次在AbstractAutowireCapableBeanFactorydoCreateBean()方法中看到完整的生命周期调用链时,突然理解了Rod Johnson的设计哲学:框架的强大不在于功能堆砌,而在于扩展性的精妙平衡。Bean生命周期的价值体现在三个维度: 1. 标准化:通过6大阶段、14个扩展点构建了工业级的对象管理流水线; 2. 可观测:每个节点开放干预能力,使开发者能像调试本地代码一样控制容器行为; 3. 生态兼容:为Spring Boot自动装配、Cloud配置中心等提供了底层支撑。

技术启示录

  • 理解BeanPostProcessor,就抓住了Spring扩展的命脉;
  • 掌握作用域与生命周期的关系,能避免90%的资源泄漏问题;
  • 阅读AbstractAutowireCapableBeanFactory源码,是进阶Spring架构师的必经之路。

最后分享一次教训:曾因在@PostConstruct中调用远程服务导致系统启动超时。后改为@EventListener(ContextRefreshedEvent.class),完美解耦初始化与启动流程——这,正是理解生命周期的价值所在

6.1 参考源码与延伸阅读

  1. Spring官方生命周期文档:BeanFactory Javadoc
  2. 本文代码示例仓库:github.com/spring-projects/spring-framework/tree/main/spring-beans
  3. 生命周期调试工具:Spring Lifecycle Debugger
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、Bean生命周期全景
    • 1.1 核心流程图(建议收藏)
  • 二、深度拆解:6大阶段源码级剖析
    • 2.1 实例化(Instantiation)—— 生命的起点
    • 2.2 属性填充(Population)—— 依赖注入的本质
    • 2.3 Aware接口回调—— 获取容器“内幕”
    • 2.4 初始化(Initialization)—— 三种方式与执行顺序
    • 2.5 BeanPostProcessor后置处理——AOP的诞生地
    • 2.6 销毁(Destruction)—— 优雅关闭资源
  • 三、扩展点全景:5类扩展接口详解
    • 3.1 扩展接口阶段应用
  • 四、作用域对生命周期的影响
    • 4.1 单例(Singleton) vs 原型(Prototype)
    • 4.2 Web作用域的特殊性
  • 五、企业级避坑指南
    • 5.1 高频问题与解决方案
    • 5.2 性能优化关键点
  • 六、总结
    • 6.1 参考源码与延伸阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档