Spring生命周期管理
Spring生命周期管理这是面试的热门问题主要提问点在于Spring的回调事件执行顺序。这些回调事件可以分为两类初始化阶段销毁阶段下面我们用一个小项目来试验一下,看看具体的执行顺序并且通过调试追溯到Spring容器源码。项目准备JDK版本 Amazon Corretto 17.0.19Spring Boot 版本 3.5.14版本兼容性说明本文讲解的 Spring Bean 生命周期核心原理适用于Spring Framework 5.x / 6.x和Spring Boot 2.x / 3.x。不同版本的源码路径和类名可能略有差异但生命周期管理的机制和回调顺序完全一致。初始化阶段实验实验代码packagecn.edu.ncepu.springmvd.demo;importjakarta.annotation.PostConstruct;importorg.springframework.beans.BeansException;importorg.springframework.beans.factory.*;importorg.springframework.context.ApplicationContext;importorg.springframework.context.ApplicationContextAware;importorg.springframework.context.ApplicationStartupAware;importorg.springframework.core.metrics.ApplicationStartup;importorg.springframework.stereotype.Component;ComponentpublicclassTestInitBeanimplementsBeanNameAware,BeanClassLoaderAware,BeanFactoryAware,ApplicationStartupAware,ApplicationContextAware,InitializingBean{OverridepublicvoidsetBeanName(Stringname){System.out.println(TestInitBean.setBeanName());}OverridepublicvoidsetBeanClassLoader(ClassLoaderclassLoader){System.out.println(TestInitBean.setBeanClassLoader());}OverridepublicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{System.out.println(TestInitBean.setBeanFactory());}OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{System.out.println(TestInitBean.setApplicationContext());}OverridepublicvoidsetApplicationStartup(ApplicationStartupapplicationStartup){System.out.println(TestInitBean.setApplicationStartup());}PostConstructpublicvoidinit(){System.out.println(TestInitBean.init());}OverridepublicvoidafterPropertiesSet()throwsException{System.out.println(TestInitBean.afterPropertiesSet());}}回调调试在Aware回调中加断点发现上层方法是o.s.b.f.s.AbstractAutowireCapableBeanFactory.initializeBean()的源码protectedObjectinitializeBean(StringbeanName,Objectbean,NullableRootBeanDefinitionmbd){invokeAwareMethods(beanName,bean);ObjectwrappedBeanbean;if(mbdnull||!mbd.isSynthetic()){wrappedBeanapplyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);}try{invokeInitMethods(beanName,wrappedBean,mbd);}catch(Throwableex){thrownewBeanCreationException((mbd!null?mbd.getResourceDescription():null),beanName,ex.getMessage(),ex);}if(mbdnull||!mbd.isSynthetic()){wrappedBeanapplyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);}returnwrappedBean;}从源码里可以看到以下四个关键私有方法invokeAwareMethodsapplyBeanPostProcessorsBeforeInitializationinvokeInitMethodsapplyBeanPostProcessorsAfterInitialization调试过程中可以看到调用了以下三个方法invokeAwareMethods,作用是调用BeanNameAware、BeanClassLoaderAware、BeanFactoryAware三大回调applyBeanPostProcessorsBeforeInitialization作用是调用其他Aware回调和调用PostConstruct注解的方法,只不过BeanPostProcessor不一样invokeInitMethods作用是执行afterPropertiesSet()方法和自定义的init-method实验结果TestInitBean.setBeanName() TestInitBean.setBeanClassLoader() TestInitBean.setBeanFactory() TestInitBean.setApplicationStartup() TestInitBean.setApplicationContext() TestInitBean.init() TestInitBean.afterPropertiesSet()实验结果验证了源码和调试的结论。结论先执行BeanNameAware、BeanClassLoaderAware、BeanFactoryAware三个回调方法再通过ApplicationContextAwareProcessor执行其他Aware的回调方法接下来通过CommonAnnotationBeanPostProcessor执行PostConstruct方法最后执行InitializingBean.afterPropertiesSet()销毁实验对于销毁实验我们不用Component注解在实际项目中也不推荐销毁处理的Spring bean使用类上注解来声明。这里推荐使用Bean注解来声明因为Bean注解配置更加丰富。需要注意的是如果实现了AutoCloseable接口destroyMethod属性最好明确指定为“close”因为Spring源码有这么一段publicDisposableBeanAdapter(Objectbean,StringbeanName,RootBeanDefinitionbeanDefinition,ListDestructionAwareBeanPostProcessorpostProcessors){// 省略一些代码this.invokeAutoCloseable(beaninstanceofAutoCloseableCLOSE_METHOD_NAME.equals(destroyMethodNames[0]));// 省略一些代码}实验代码首先改动下实验的main方法SpringBootApplicationpublicclassMain{publicstaticvoidmain(String[]args){try(ConfigurableApplicationContextcontextSpringApplication.run(Main.class,args)){System.out.println(context);}}Bean(destroyMethodclose)publicTestDestroyBeantestDestroyBean(){returnnewTestDestroyBean();}}其次是bean的代码packagecn.edu.ncepu.springmvd.demo;importjakarta.annotation.PreDestroy;importorg.springframework.beans.factory.DisposableBean;publicclassTestDestroyBeanimplementsDisposableBean,AutoCloseable{Overridepublicvoiddestroy()throwsException{System.out.println(TestDestroyBean.destroy());}PreDestroypublicvoidpreDestroy(){System.out.println(TestDestroyBean.preDestroy());}Overridepublicvoidclose(){System.out.println(TestDestroyBean.close());}}回调调试在代码中加了断点之后我们知道了Spring容器执行销毁回调的源码位置。o.s.b.f.s.DisposableBeanAdapter.destroy()。通过 DestructionAwareBeanPostProcessor 执行 PreDestroy 注解方法执行 DisposableBean.destroy() 方法执行自定义的 destroyMethod如 AutoCloseable.close()实验结果TestDestroyBean.preDestroy() TestDestroyBean.destroy() TestDestroyBean.close()结论先执行PreDestroy注解方法再执行DisposableBean的回调方法最后执行AutoCloseable的close方法总结Spring生命周期分两大过程创建和销毁。创建过程又分为三个阶段实例化(Instantiation)填充属性(Populate Bean)初始化(Initialization)而初始化相关的回调事件全部位于初始化(Initialization)阶段销毁相关的回调事件位于销毁阶段。初始化阶段先执行Bean*Aware回调接着执行其他Aware回调下一步执行PostConstruct注解方法最后执行InitializingBean的回调方法销毁阶段销毁阶段先执行PreDestroy注解方法接着执行DisposableBean的回调方法最后执行AutoCloseable的close方法