SpringBoot Bean生命周期
创始人
2025-05-30 00:39:35
0
注:Spring Boot Bean的生命周期,什么是Bean的生命周期,就是Bean从创建到销毁的过程。

Bean的生命周期过程描述

我们先看一下Bean的生命周期过程中都会经历些什么,我先简单解释一下,后面我们通过源码进行详细解释。首先Spring在实例化Bean的时候,会先调用它的构造函数,进行Bean的实例化,然后进行Bean的初始化,Bean的初始化经过三个阶段初始化之前(applyBeanPostProcessorsBeforeInitialization),其次是进行初始化(invokeInitMethods),最后是初始化之后(postProcessAfterInitialization),这就是Bean的初始化过程;然后就开始利用Bean进行业务逻辑处理,最后容器正常关闭,Spring开始销毁Bean,Bean的销毁过程相对比较简单,调用DisposableBeanAdapter.destroy()方法,该方法中有三个地方比较重要,分别触发Bean的生命周期方法,它们是:processor.postProcessBeforeDestruction(this.bean, this.beanName);

((DisposableBean) bean).destroy();

invokeCustomDestroyMethod(this.destroyMethod);

下面我把用图片来进行直观展示:

实例运行

User类,这里就是普通的一个Bean,用来添加到容器中,观察其生命周期

package com.itbofeng.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class User implements InitializingBean , DisposableBean {private String name;public User() {System.out.println("调用Bean的函数(constructor)");}public String getName() {return name;}public void setName(String name) {System.out.println("调用Bean的函数(setName/setAttribute)");this.name = name;}@PostConstructpublic void postConstruct(){System.out.println("调用Bean的函数(postConstruct)");}//MainConfig中@Bean 的initMethodpublic void initMethod(){System.out.println("调用Bean的函数(initMethod)");}//InitializingBean接口的方法afterPropertiesSet@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("调用Bean的函数(afterPropertiesSet)");}@PreDestroypublic void preDestroy(){System.out.println("调用Bean的函数(preDestroy)");}//DisposableBean接口的方法destroy@Overridepublic void destroy() throws Exception {System.out.println("调用Bean的函数(destroy)");}//MainConfig中@Bean 的destroyMethodpublic void destroyMethod(){System.out.println("调用Bean的函数(destroyMethod)");}
}

CustomBeanPostProcessor类,用来观察BeanPostProcessor的运行时期

package com.itbofeng.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {@Nullable@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if(bean.getClass()==User.class){System.out.println("调用postProcessBeforeInitialization...");}return bean;}@Nullable@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if(bean.getClass()==User.class){System.out.println("调用postProcessAfterInitialization...");}return bean;}
}

MainConfig类,SpringBoot程序运行的主类,并将User和CustomBeanPostProcessor 加入到容器中

package com.itbofeng;
import com.itbofeng.bean.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class MainConfig {public static void main(String[] args) {SpringApplication.run(MainConfig.class,args);}@Bean(initMethod = "initMethod",destroyMethod = "destroyMethod")public User user(){return new User();}
}

运行结果查看

源码解析

初始化过程

首先我们将断点打到CustomBeanPostProcessor.postProcessBeforeInitialization的第一行代码,然后我看一下其方法调用栈:

主要包括两个地方,一个是容器刷新,第二个是初始化Bean,我们先对这容器刷新的源码进行简单查看

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}

注意finishBeanFactoryInitialization,上面说明也解释说该方法的作用是初始化所有剩下的非懒加载的单例Bean,从该描述也可以知道,懒加载和原型的Bean在该阶段并不会被加载,这部分代码是Spring容器刷新时的代码,也是Spring IOC比较核心的代码,在学习后面中,慢慢将该部分的代码慢慢学习,接下来我们看一下初始化Bean部分的代码:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {//对实现了Aware接口的方法进行执行,方法就在下方,使用方法直接实现对应的Aware接口即可if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//执行实现了BeanPostProcessor的postProcessBeforeInitialization方法wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//执行初始化方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {//执行实现了BeanPostProcessor的postProcessAfterInitialization方法wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;
}private void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}
}protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {boolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {if (logger.isDebugEnabled()) {logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");}//调用InitializingBean的afterPropertiesSet方法if (System.getSecurityManager() != null) {try {AccessController.doPrivileged((PrivilegedExceptionAction) () -> {((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());}catch (PrivilegedActionException pae) {throw pae.getException();}}else {((InitializingBean) bean).afterPropertiesSet();}}//调用@Bean制定的的initMethod方法if (mbd != null && bean.getClass() != NullBean.class) {String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {invokeCustomInitMethod(beanName, bean, mbd);}}
}

以上就是初始化阶段,我们会发现初始化过程中没有@PostConstruct注解标注的方法,那是因为对@PostConstruct的处理也是BeanPostProcessor的实现类InitDestroyAnnotationBeanPostProcessor,那么我们就应该有疑问为什么InitDestroyAnnotationBeanPostProcessor.postProcessBeforeDestruction为什么会在CustomBeanPostProcessor.postProcessBeforeInitialization之后进行,是因为如果不指定顺序默认我们的getOrder为0,而InitDestroyAnnotationBeanPostProcessor的getOrder为Ordered.LOWEST_PRECEDENCE=2147483647,getOrder越大则,优先级越低,所以我们自定义的在其之前,至此初始化部分结束。

下面我们简单看一下销毁阶段:

public void destroy() {//处理@PreDestroy注解注释的方法if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {processor.postProcessBeforeDestruction(this.bean, this.beanName);}}//处理实现了DisposableBean接口的destroy的方法if (this.invokeDisposableBean) {if (logger.isDebugEnabled()) {logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");}try {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedExceptionAction) () -> {((DisposableBean) bean).destroy();return null;}, acc);}else {((DisposableBean) bean).destroy();}}catch (Throwable ex) {String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";if (logger.isDebugEnabled()) {logger.warn(msg, ex);}else {logger.warn(msg + ": " + ex);}}}//处理@Bean指定的destroyMethod方法if (this.destroyMethod != null) {invokeCustomDestroyMethod(this.destroyMethod);}else if (this.destroyMethodName != null) {Method methodToCall = determineDestroyMethod(this.destroyMethodName);if (methodToCall != null) {invokeCustomDestroyMethod(methodToCall);}}
}

结束语

至此,我们Bean的生命周期探索初步结束,后面再做进一步深入学习,在学习本节课时要多进行调试,断点跟踪,会更加有效果。另外无论是在初始化还是在结束时都是处理的单例的Bean,而且在初始化时,处理的Bean还是非懒加载的,所以需要特殊说明:非懒加载的单实例Bean的生命周期如上;懒加载的单实例Bean是在第一次获取进行初始化过程;原型Bean是在每次获取时都进行初始化,而且Spring容器不会管理器销毁。

相关内容

热门资讯

一文了解GPU并行计算CUDA 了解GPU并行计算CUDA一、CUDA和GPU简介二、GPU工作原理与结构2.1、基础GPU架构2....
贵阳最新学区划分,最新或202... 贵阳公办小学招生范围按照义务教育免试就近入学原则,市区公办小学实行依街道划片招生。本文为您介绍贵阳小...
遵义最新学区划分,最新或202... 遵义公办小学招生范围按照义务教育免试就近入学原则,市区公办小学实行依街道划片招生。本文为您介绍遵义小...
安顺最新学区划分,最新或202... 安顺公办小学招生范围按照义务教育免试就近入学原则,市区公办小学实行依街道划片招生。本文为您介绍安顺小...
六盘水最新学区划分,最新或20... 百年教育网小编为您整理了关于六盘水市幼升小学区划分详情的相关信息,希望对您有帮助,想了解更多请继续关...
遍历二叉树线索二叉树 遍历二叉树 遍历定义 顺着某一条搜索路径寻访二叉树中的每一个结点,使得每个节点均被依次...
springboot简介和项目... Java知识点总结:想看的可以从这里进入 目录SpringBoot1、简介和原理1....
最新或2023(历届)嘉祥教育... 信息时报讯 面临中考,初三学生陈黎的父母十分发愁。一是孩子成绩并不拔尖,另外,父母虽然有心让儿子出...
“牛孩儿”“每天一题”助你提升... “小升初”的战鼓越擂越响,你准备好了吗?不要着急,自4月29日起,中原网教育频道官方微信“中原教育”...
这是一封发给西安小升初家长的邀... 秦学·伊顿交大校区4月9日晚上举办的小升初讲座圆满结束了,回顾讲座现场的瞬间,小编有一些小小的感动。...
四大法宝护航“528冲刺班”巨... 又是一个四月,春风扑面,鲜花盛开。又是一届小考,竞争激烈,埋头伏案。又是一轮冲刺,全力以赴,舍我其谁...
小升初数学面谈题型归纳 小升初... 数学在小升初择校中的重要性可以说是毋庸置疑的。很多一线名校例如二中应元、六中珠江、广大附等都对数学情...
vue2+3 pinia v... 1. 为什么要学习vue1.官网https://v3.cn.vuejs.org/guide/migr...
防雷设计、防雷检测为什么选同为... 随着现代科技的不断发展,电子设备得到广泛应用,而雷电等自然灾害也越来越频...
最新或2023(历届)快乐的下...  今天下午,我去了隋唐遗址。那里好美丽;有小河;有草地,小河里有鱼,有虾。  我先说河,有的河水清澈...
最新或2023(历届)6年级数...  篇一  今天,妈妈给我出了一道题,题目是这样的:“一头牛可换6头猪,2头猪可换10只羊,三只羊可换...
本次小升初直升考试试卷分析这就... 还记得前几天预告的小升初直升考试吗?这次的考试对于小学六年级的孩子们来说,是非常重要的。家长朋友们也...
西安小升初528预录来了! 西... 相信大家这几天除了被各种各样的学校参观弄得有点晕,到底这参观是几个意思呢!是有暗示还是没暗示,其实这...
最新或2023(历届)认真积极...   今天妈妈带我去学英语,上课我认真听盘,积极的举手回答问题,下课后妈妈表扬了我,我很高兴。回到家我...
【js】多分支语句练习(2) 个人名片: 😊作者简介:一名大一在校生,w...