Spring 源码系列(7): Bean 生命周期:实例化 → 属性填充 → 初始化 → 销毁

📅 2026/7/22 12:04:41
Spring 源码系列(7): Bean 生命周期:实例化 → 属性填充 → 初始化 → 销毁
引子面试经典题“说一下 Spring Bean 的生命周期。”多数回答只到实例化、初始化漏掉三块关键内容①Aware接口回调的精确时机②PostConstruct与init-method的先后顺序③销毁阶段PreDestroy/DisposableBean/destroy-method。本篇把从new到destroy的完整链路补全并给出可背的九步法。一句话结论完整生命周期 实例化 → 提前暴露 → 属性填充 → Aware 回调 → BPP 前置(PostConstruct) →InitializingBean/init-method → BPP 后置(AOP) →可用→ 销毁(PreDestroy/DisposableBean/destroy-method)。注意ApplicationContextAware不在invokeAwareMethods里它由ApplicationContextAwareProcessorBPP注入。前置知识本篇是上一篇initializeBean的横向展开创建三段实例化/填充已在第 6 篇讲清。initializeBean只覆盖初始化这一段销毁由容器关闭时独立触发。只有单例Bean 的生命周期被容器完整管理原型prototypeBean 容器只负责创建到初始化销毁不归容器管。一、生命周期九步全景阶段触发点对应接口 / 注解① 实例化createBeanInstance构造器反射② 提前暴露addSingletonFactory仅单例解决循环依赖③ 属性填充populateBeanAutowired/Resource/property④ Aware 回调invokeAwareMethodsBeanNameAware/BeanFactoryAware/BeanClassLoaderAware⑤ BPP 前置applyBeanPostProcessorsBeforeInitializationPostConstruct⑥ 初始化方法invokeInitMethodsInitializingBean.afterPropertiesSet 自定义init-method⑦ BPP 后置applyBeanPostProcessorsAfterInitializationAOP 代理在此生成⑧ 就绪可用——返回最终对象可能是代理⑨ 销毁DisposableBeanAdapter.destroyPreDestroy/DisposableBean.destroy/ 自定义destroy-method⚠️易错点ApplicationContextAware、EnvironmentAware、MessageSourceAware等不在④ 的invokeAwareMethods里。它们由ApplicationContextAwareProcessor一个BeanPostProcessor在第 5 篇第 3 步注册在 ⑤ BPP 前置阶段注入。所以所有 Aware 都在初始化前这句话不严谨——要分清BeanFactory 级 Aware和ApplicationContext 级 Aware。二、初始化阶段源码invokeAwareMethods只认三个 BeanFactory 级接口privatevoidinvokeAwareMethods(StringbeanName,Objectbean){if(beaninstanceofAware){if(beaninstanceofBeanNameAware){((BeanNameAware)bean).setBeanName(beanName);}if(beaninstanceofBeanClassLoaderAware){((BeanClassLoaderAware)bean).setBeanClassLoader(getBeanClassLoader());}if(beaninstanceofBeanFactoryAware){((BeanFactoryAware)bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}}initializeBean把 ④⑤⑥⑦ 串起来protectedObjectinitializeBean(StringbeanName,Objectbean,RootBeanDefinitionmbd){invokeAwareMethods(beanName,bean);// ④ObjectwrappedBeanbean;wrappedBeanapplyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);// ⑤ PostConstructinvokeInitMethods(beanName,wrappedBean,mbd);// ⑥wrappedBeanapplyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);// ⑦ AOPreturnwrappedBean;}invokeInitMethods的顺序先InitializingBean.afterPropertiesSet再自定义init-methodprotectedvoidinvokeInitMethods(StringbeanName,Objectbean,RootBeanDefinitionmbd){if(beaninstanceofInitializingBean){((InitializingBean)bean).afterPropertiesSet();// 接口优先}if(mbd!nullStringUtils.hasLength(mbd.getInitMethodName())){invokeCustomInitMethod(beanName,bean,mbd.getInitMethodName());// init-method 在后}}三、销毁阶段源码容器关闭close()时DisposableBeanAdapter.destroy()按以下顺序执行PreDestroy标注的方法由CommonAnnotationBeanPostProcessor注册为DestructionAwareBeanPostProcessorDisposableBean.destroy()接口自定义destroy-methodXML/Bean(destroyMethod)。结论销毁顺序与初始化对称——注解PreDestroy优先于接口DisposableBean优先于自定义方法destroy-method。四、生命周期流程图五、常见误区误区正解PostConstruct属于init-method否它走 BPP 前置PostConstruct是 JSR-250init-method是InitializingBean之后的自定义方法ApplicationContextAware在invokeAwareMethods注入否由ApplicationContextAwareProcessorBPP在初始化前置阶段注入原型 Bean 也有销毁回调否容器不管理原型 Bean 的销毁需自行释放InitializingBean比init-method先执行是接口优先于自定义方法六、面试题自测完整生命周期按什么顺序至少说出 7 个关键节点。BeanNameAware/BeanFactoryAware/ApplicationContextAware分别在何时注入PostConstruct、InitializingBean.afterPropertiesSet、init-method三者执行顺序销毁阶段的执行顺序是什么为什么原型prototypeBean 的PreDestroy不生效七、Debug 小技巧在initializeBean第一行打断点Step IntoinvokeAwareMethods确认只有三个 BeanFactory 级 Aware 被回调。在applyBeanPostProcessorsBeforeInitialization处观察传入的是原始对象走完PostConstruct才返回若被 AOP 代理最终返回的是代理类。验证销毁在测试末尾调用((ConfigurableApplicationContext) ctx).close()在DisposableBeanAdapter.destroy打断电看三个销毁动作的执行次序。下篇预告第 8 篇我们回头钻populateBean阶段依赖注入DI在源码里如何发生——Autowired/Resource到底在哪一步、怎么把依赖对象塞进字段。如果这篇对你有帮助欢迎点赞 · 收藏 · 关注三连支持。Spring 源码系列共 30 篇由浅入深持续更新中。有疑问或想深挖的源码点评论区告诉我下篇见。