第18篇 · Bean生命周期全解密:从出生到销毁的完整旅程

发布时间:2026/6/28 1:30:02
第18篇 · Bean生命周期全解密:从出生到销毁的完整旅程 在前面第10篇讲 IoC 容器的时候我们提到了 Spring 如何通过三级缓存解决循环依赖——那篇的重点是“容器如何管理 Bean 的创建”。但你可能没注意到一个细节Bean 从创建到销毁中间到底经历了哪些步骤你在写代码的时候可能用过PostConstruct做初始化也可能在application.yml里配置过init-method。但这些注解和方法谁先谁后BeanPostProcessor又是在什么时候介入的如果你对这些问题没有清晰的答案那当 Bean 的初始化顺序出现问题时你就只能靠试错来排查了。这一篇我们把 Bean 从“出生”到“销毁”的完整旅程走一遍。学习目标掌握 Bean 生命周期的五个阶段实例化→属性赋值→初始化→使用→销毁理解BeanPostProcessor在初始化前后的扩展作用掌握PostConstruct和PreDestroy的使用掌握 Aware 接口族的作用BeanNameAware、BeanFactoryAware、ApplicationContextAware理解InitializingBean和DisposableBean接口正文一、生命周期全景图五个阶段一个 Spring Bean 的完整生命周期可以划分为五个大的阶段① 实例化Instantiation容器通过反射调用 Bean 的构造方法或工厂方法创建一个实例对象。此时对象已经存在但属性还是空的——相当于一个“空壳”。② 属性赋值Populate Properties容器根据 Bean 定义中的配置XML 或注解通过依赖注入为 Bean 的属性赋值。Autowired、Resource、Value等注解都是在这一阶段生效的。③ 初始化Initialization这是生命周期中最复杂的阶段包含了多个子步骤后面会详细展开Aware 接口回调 →BeanPostProcessor前置处理 →PostConstruct→InitializingBean.afterPropertiesSet()→ 自定义init-method→BeanPostProcessor后置处理。④ 使用UsageBean 完成初始化后就可以被应用程序正常使用了。它会一直驻留在容器中直到容器关闭。⑤ 销毁Destruction容器关闭时会触发 Bean 的销毁逻辑PreDestroy→DisposableBean.destroy()→ 自定义destroy-method。一张图看懂全流程容器启动 ↓ ① 实例化调用构造方法 ↓ ② 属性赋值依赖注入 ↓ ③ 初始化 ├── Aware 接口回调BeanNameAware → BeanFactoryAware → ApplicationContextAware ├── BeanPostProcessor.postProcessBeforeInitialization() ├── PostConstruct 标注的方法 ├── InitializingBean.afterPropertiesSet() ├── 自定义 init-method └── BeanPostProcessor.postProcessAfterInitialization() ↓ ④ 使用Bean 就绪提供服务 ↓ 容器关闭 ↓ ⑤ 销毁 ├── PreDestroy 标注的方法 ├── DisposableBean.destroy() └── 自定义 destroy-method二、实例化与属性赋值createBeanInstance populateBean在 Spring 源码中Bean 的实例化和属性赋值是在AbstractAutowireCapableBeanFactory类的doCreateBean()方法中完成的。我们来看简化后的源码protectedObjectdoCreateBean(StringbeanName,RootBeanDefinitionmbd,Object[]args){// 第一步实例化 BeanWrapperinstanceWrappercreateBeanInstance(beanName,mbd,args);ObjectbeaninstanceWrapper.getWrappedInstance();// 提前暴露用于解决循环依赖 addSingletonFactory(beanName,()-getEarlyBeanReference(beanName,mbd,bean));// 第二步属性赋值 populateBean(beanName,mbd,instanceWrapper);// 第三步初始化 exposedObjectinitializeBean(beanName,exposedObject,mbd);returnexposedObject;}createBeanInstance()根据 Bean 的定义选择合适的构造方法或工厂方法通过反射创建 Bean 实例。如果 Bean 有多个构造方法Spring 会根据参数列表自动选择最匹配的一个。populateBean()对刚刚创建的“空壳”对象进行属性填充。它处理的内容包括XML 中property标签配置的属性Autowired、Inject、Resource标注的字段和方法Value标注的配置属性注入属性赋值完成之后Bean 的依赖关系已经全部建立好了但 Bean 还没有执行任何初始化逻辑。三、初始化三阶段从 Aware 到 BeanPostProcessorinitializeBean()方法是初始化阶段的核心入口。它的内部逻辑可以拆解为三个大的步骤protectedObjectinitializeBean(StringbeanName,Objectbean,RootBeanDefinitionmbd){// 阶段一Aware 接口回调 invokeAwareMethods(beanName,bean);// 阶段二BeanPostProcessor 前置处理 ObjectwrappedBeanapplyBeanPostProcessorsBeforeInitialization(bean,beanName);// 阶段三执行初始化方法 invokeInitMethods(beanName,wrappedBean,mbd);// 阶段四BeanPostProcessor 后置处理 wrappedBeanapplyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);returnwrappedBean;}阶段一Aware 接口回调如果 Bean 实现了某个 Aware 接口Spring 会在这个阶段调用对应的回调方法让 Bean 感知容器的某些信息。常见的 Aware 接口及其回调顺序Aware 接口回调方法注入的内容BeanNameAwaresetBeanName(String name)Bean 在容器中的名称BeanClassLoaderAwaresetBeanClassLoader(ClassLoader)加载当前 Bean 的类加载器BeanFactoryAwaresetBeanFactory(BeanFactory)当前 BeanFactory 实例ApplicationContextAwaresetApplicationContext(ApplicationContext)当前 ApplicationContext 实例关键认知Aware 接口的调用是“内置功能”不需要任何额外的后置处理器支持。而Autowired的解析需要AutowiredAnnotationBeanPostProcessor属于“扩展功能”。阶段二BeanPostProcessor 前置处理applyBeanPostProcessorsBeforeInitialization()会遍历容器中所有注册的BeanPostProcessor依次调用它们的postProcessBeforeInitialization()方法。这个方法允许你在 Bean执行任何初始化逻辑之前对 Bean 实例进行修改——比如检查标记接口、修改属性值、或者返回一个代理对象。阶段三执行初始化方法invokeInitMethods()是初始化阶段的核心它按固定顺序执行三种初始化回调① PostConstruct 标注的方法 ② InitializingBean.afterPropertiesSet() ③ 自定义 init-methodBean(initMethod xxx) 或 XML 配置PostConstructJSR-250 规范定义的注解在依赖注入完成后执行。这是目前最主流的初始化方式。InitializingBean.afterPropertiesSet()Spring 提供的接口方法在所有属性被设置之后、自定义 init-method 之前调用。自定义init-method通过Bean(initMethod init)或 XML 的init-method属性指定。这是最传统的配置方式但现在用得越来越少了。阶段四BeanPostProcessor 后置处理applyBeanPostProcessorsAfterInitialization()在所有初始化逻辑完成后调用。这是 Bean 在“正式投入使用”之前的最后一次修改机会。Spring 内部大量使用BeanPostProcessor来实现 AOP——AnnotationAwareAspectJAutoProxyCreator就是一个BeanPostProcessor它在postProcessAfterInitialization()中检查 Bean 是否需要代理如果需要就返回一个代理对象。四、Aware 接口的作用让 Bean “感知”容器Aware 接口是 Spring 提供的一组“感知”接口让 Bean 能够获取容器中的基础设施对象。为什么要用 Aware 接口在大多数情况下你的 Bean 不需要知道容器的存在——只管处理自己的业务逻辑就行了。但有些场景下Bean 确实需要访问容器需要获取当前 Bean 的名称比如记录日志时需要获取ApplicationContext来手动获取其他 Bean需要获取BeanFactory来做一些高级操作Aware 接口的调用时机在属性赋值完成之后、BeanPostProcessor前置处理之前。也就是说Aware 接口回调时Bean 的所有依赖已经注入完毕但初始化逻辑还没有执行。一个典型的 Aware 接口使用示例ComponentpublicclassMyBeanimplementsBeanNameAware,ApplicationContextAware{privateStringbeanName;privateApplicationContextapplicationContext;OverridepublicvoidsetBeanName(Stringname){this.beanNamename;System.out.println(Bean 名称: name);}OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext){this.applicationContextapplicationContext;System.out.println(ApplicationContext 已注入);}}五、BeanPostProcessor 原理每个 Bean 初始化前后的“拦截器”BeanPostProcessor是 Spring 提供的一个容器级别的扩展接口。它的定义非常简单publicinterfaceBeanPostProcessor{// 初始化之前调用defaultObjectpostProcessBeforeInitialization(Objectbean,StringbeanName){returnbean;}// 初始化之后调用defaultObjectpostProcessAfterInitialization(Objectbean,StringbeanName){returnbean;}}执行时机postProcessBeforeInitialization在 Aware 接口回调之后、PostConstruct/afterPropertiesSet()/init-method之前执行postProcessAfterInitialization在所有初始化逻辑之后执行典型用途用途说明返回代理对象AOP 通过postProcessAfterInitialization返回代理对象替换原始 Bean属性修改在初始化前修改 Bean 的某些属性标记接口检测检查 Bean 是否实现了某个标记接口做额外处理日志/监控记录 Bean 的创建和初始化信息重要特性ApplicationContext可以自动检测实现了BeanPostProcessor的 Bean并在容器启动时注册它们。这意味着你只需要把BeanPostProcessor声明为一个普通的 Spring Bean加Component它就会自动生效。多个 BeanPostProcessor 的执行顺序按Order注解或Ordered接口指定的顺序执行数字越小越先执行。六、销毁阶段PreDestroy → DisposableBean → destroy-method当容器关闭时调用context.close()Spring 会触发 Bean 的销毁流程。销毁阶段的执行顺序是① PreDestroy 标注的方法 ② DisposableBean.destroy() ③ 自定义 destroy-methodBean(destroyMethod xxx) 或 XML 配置PreDestroyJSR-250 规范定义的注解在容器销毁 Bean 之前执行用于释放资源。DisposableBean.destroy()Spring 提供的接口方法在PreDestroy之后调用。自定义destroy-method通过Bean(destroyMethod cleanup)或 XML 的destroy-method属性指定。注意销毁阶段只在单例 Bean上生效。对于原型PrototypeBeanSpring 容器不负责管理它们的销毁——你需要自己手动调用销毁逻辑。代码示例示例一完整生命周期日志追踪这个示例在一个 Bean 中实现所有生命周期回调打印日志观察执行顺序。环境Spring Boot 3.4.x / Spring Framework 6.xJDK 17Bean 实现类packagecom.example.demo.lifecycle;importjakarta.annotation.PostConstruct;importjakarta.annotation.PreDestroy;importorg.springframework.beans.BeansException;importorg.springframework.beans.factory.BeanFactory;importorg.springframework.beans.factory.BeanFactoryAware;importorg.springframework.beans.factory.BeanNameAware;importorg.springframework.beans.factory.DisposableBean;importorg.springframework.beans.factory.InitializingBean;importorg.springframework.context.ApplicationContext;importorg.springframework.context.ApplicationContextAware;importorg.springframework.stereotype.Component;ComponentpublicclassLifecycleBeanimplementsBeanNameAware,BeanFactoryAware,ApplicationContextAware,InitializingBean,DisposableBean{publicLifecycleBean(){System.out.println([1] 构造方法 —— 实例化);}OverridepublicvoidsetBeanName(Stringname){System.out.println([2] BeanNameAware.setBeanName() —— Bean 名称: name);}OverridepublicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{System.out.println([3] BeanFactoryAware.setBeanFactory() —— BeanFactory 已注入);}OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{System.out.println([4] ApplicationContextAware.setApplicationContext() —— ApplicationContext 已注入);}PostConstructpublicvoidpostConstruct(){System.out.println([5] PostConstruct —— 初始化方法JSR-250);}OverridepublicvoidafterPropertiesSet()throwsException{System.out.println([6] InitializingBean.afterPropertiesSet() —— Spring 接口初始化);}/** * 自定义 init-method —— 在 Bean 注解中指定 */publicvoidcustomInit(){System.out.println([7] 自定义 init-method —— Bean(initMethod \customInit\));}/** * 业务方法 */publicvoiddoSomething(){System.out.println([8] 业务方法 —— Bean 已就绪正在使用);}PreDestroypublicvoidpreDestroy(){System.out.println([9] PreDestroy —— 销毁前回调JSR-250);}Overridepublicvoiddestroy()throwsException{System.out.println([10] DisposableBean.destroy() —— Spring 接口销毁);}/** * 自定义 destroy-method —— 在 Bean 注解中指定 */publicvoidcustomDestroy(){System.out.println([11] 自定义 destroy-method —— Bean(destroyMethod \customDestroy\));}}配置类注册 Bean 并指定自定义的 init/destroy 方法packagecom.example.demo.config;importcom.example.demo.lifecycle.LifecycleBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;ConfigurationpublicclassLifecycleConfig{Bean(initMethodcustomInit,destroyMethodcustomDestroy)publicLifecycleBeanlifecycleBean(){returnnewLifecycleBean();}}启动类packagecom.example.demo;importcom.example.demo.lifecycle.LifecycleBean;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.ConfigurableApplicationContext;SpringBootApplicationpublicclassDemoApplication{publicstaticvoidmain(String[]args){ConfigurableApplicationContextcontextSpringApplication.run(DemoApplication.class,args);// 获取 Bean 并执行业务方法LifecycleBeanbeancontext.getBean(LifecycleBean.class);bean.doSomething();// 关闭容器触发销毁context.close();}}控制台输出[1] 构造方法 —— 实例化 [2] BeanNameAware.setBeanName() —— Bean 名称: lifecycleBean [3] BeanFactoryAware.setBeanFactory() —— BeanFactory 已注入 [4] ApplicationContextAware.setApplicationContext() —— ApplicationContext 已注入 [5] PostConstruct —— 初始化方法JSR-250 [6] InitializingBean.afterPropertiesSet() —— Spring 接口初始化 [7] 自定义 init-method —— Bean(initMethod customInit) [8] 业务方法 —— Bean 已就绪正在使用 [9] PreDestroy —— 销毁前回调JSR-250 [10] DisposableBean.destroy() —— Spring 接口销毁 [11] 自定义 destroy-method —— Bean(destroyMethod customDestroy)关键观察Aware 接口的回调顺序是BeanNameAware→BeanFactoryAware→ApplicationContextAware初始化顺序是PostConstruct→InitializingBean.afterPropertiesSet()→ 自定义init-method销毁顺序是PreDestroy→DisposableBean.destroy()→ 自定义destroy-methodPostConstruct和PreDestroy是 JSR-250 规范定义的不依赖 Spring 特有的接口示例二自定义 BeanPostProcessor这个示例实现了一个自定义的BeanPostProcessor对所有 Bean 初始化前后打印日志。packagecom.example.demo.processor;importorg.springframework.beans.BeansException;importorg.springframework.beans.factory.config.BeanPostProcessor;importorg.springframework.stereotype.Component;ComponentpublicclassLoggingBeanPostProcessorimplementsBeanPostProcessor{OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{// 在初始化之前执行System.out.println( [前置] beanName - 准备初始化);returnbean;// 可以返回修改后的 Bean或直接返回原对象}OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{// 在初始化之后执行System.out.println(✅ [后置] beanName - 初始化完成);returnbean;// 可以返回代理对象替换原 Bean}}关键观察postProcessBeforeInitialization的输出出现在PostConstruct之前postProcessAfterInitialization的输出出现在自定义init-method之后这个处理器会对所有 Bean生效——这就是“容器级别扩展”的含义实际应用场景Spring 的 AOP 就是通过BeanPostProcessor实现的。AnnotationAwareAspectJAutoProxyCreator在postProcessAfterInitialization中检查 Bean 是否需要代理如果需要就返回一个代理对象。新手错误 vs 正确姿势错误表象根本原因正确姿势在构造方法中注入依赖失败依赖为null构造方法执行时依赖尚未被注入使用构造方法注入时Spring 会在构造方法执行时传入依赖如果需要在构造方法后执行逻辑使用PostConstructPostConstruct方法被调用多次误解了PostConstruct的调用时机或者 Bean 被多次实例化每个 Bean 的PostConstruct只调用一次。如果发现多次调用检查 Bean 是否被定义为原型Prototype作用域或者容器中有多个同类型的 Bean在BeanPostProcessor.postProcessBeforeInitialization中返回了null导致后续操作出现NullPointerException未理解BeanPostProcessor的返回值会被继续使用始终返回处理后的 Bean 对象不要返回null。如果不需要修改直接返回原对象原型PrototypeBean 的PreDestroy不执行原型 Bean 的销毁不由 Spring 管理原型 Bean 需要自己负责资源释放或者在业务代码中手动调用销毁方法Autowired在PostConstruct中正常工作但在构造方法中失效构造方法执行在属性注入之前PostConstruct执行在属性注入之后构造方法只用于接收构造参数注入初始化逻辑放在PostConstruct中疑难深度追问Q1BeanPostProcessor和InitializingBean的执行顺序是怎样的完整顺序是BeanPostProcessor.postProcessBeforeInitialization()PostConstruct通过CommonAnnotationBeanPostProcessor触发InitializingBean.afterPropertiesSet()自定义init-methodBeanPostProcessor.postProcessAfterInitialization()所以BeanPostProcessor的postProcessBeforeInitialization在InitializingBean之前执行postProcessAfterInitialization在InitializingBean之后执行。Q2为什么 Spring 不直接在构造方法中完成所有初始化工作因为构造方法执行时依赖可能尚未完全就绪。Spring 的生命周期是分阶段设计的构造方法创建对象实例此时依赖还没有注入属性赋值注入依赖Autowired在这一步生效初始化执行业务初始化逻辑此时所有依赖都已就绪如果所有初始化逻辑都在构造方法中完成那么在构造方法执行时被Autowired注入的依赖还是null——这会导致NullPointerException。分阶段设计让每个阶段各司其职互不干扰。Q3ApplicationContextAware和Autowired注入ApplicationContext有什么区别维度ApplicationContextAwareAutowired ApplicationContext实现方式内置功能由 Spring 容器直接回调通过AutowiredAnnotationBeanPostProcessor处理调用时机属性赋值之后、BeanPostProcessor前置处理之前属性赋值阶段与Autowired其他字段一起是否依赖后置处理器否是需要AutowiredAnnotationBeanPostProcessor实际上Autowired注入ApplicationContext晚于ApplicationContextAware的回调因为 Aware 接口的回调在属性赋值完成后立即执行而Autowired的处理是属性赋值阶段的一部分。思考与延伸动手验证运行示例一的完整代码观察控制台输出是否与文中列出的顺序一致。可以尝试调整 Bean 的配置比如去掉Component改用 XML 配置观察执行顺序是否有变化。思考题如果一个 Bean 的PostConstruct方法中抛出了异常后续的InitializingBean.afterPropertiesSet()和自定义init-method还会执行吗容器会如何处理这个 Bean延伸阅读Spring 官方文档中关于BeanPostProcessor和BeanFactoryPostProcessor的区别有详细说明——前者作用于 Bean实例后者作用于 Bean定义BeanDefinition执行时机完全不同。参考与延伸阅读Spring Framework.BeanPostProcessor Interface. Spring Framework Javadoc, 6.0.xSpring Framework.Container Extension Points — BeanPostProcessor. Spring Framework Documentation阿里云开发者社区.Spring Bean生命周期执行流程与源码原理分析. 2024-10-11腾讯云.深度解析Spring Bean生命周期全流程从创建到销毁的15步. 2025-08-27腾讯云.吃透 Spring Bean 生命周期从源码底层到实战落地. 2026-04-14阿里云开发者社区.深入Spring原理-4.Aware接口、初始化和销毁执行顺序. 2024-01-08