Springframework-ioc学习(四)之Bean生命周期

本文深入探讨Spring框架中Bean的生命周期,包括BeanFactory如何将BeanDefinition转换为Bean对象、Bean对象的生命周期及其管理方式。详细解释了Bean的创建、依赖注入、初始化及销毁等关键阶段。

在面试的时候,稍微高级一点的面试官,经常会问你对框架的源码掌握程度,而大部分会问你Spring,而关于Spring的问题,大多数会问到Spring中IOC容器管理Bean的生命周期。如果没有仔细阅读过Spring源码的同学是很难讲这个问题彻底说清楚的,如果只是从一些论坛看过类似的文章虽然有短期效果流程能说出来,但其实并没有掌握,因为其内心还没有一个直线能把断断续续的知识点给串联起来,所以很容易忘记。为了讲清楚这部分内容,小编在前3篇文章中已经做了大量的铺垫工作。

  1. 第一篇我们讲了xml配置文件是如何被Spring给读取成Java对象也就是解析XML为Document Springframework学习(一)之Xml配置文件加载

  2. 第二篇我们讲了Document是如何被Spring的解析器解析成Bean的元数据BeanDefinition Springframework学习(二)之BeanDefinition注册

  3. 第三篇我们又讲了Spring是如何给我们开发者提供切入点去最后调整读取到的BeanDefinition Springframework-ioc学习(三)之最后修改BeanDefinition的机会

那么这篇我们就要开始讲BeanDefinition是如何被转换成Bean对象及Bean对象的生命周期。

注意

感兴趣的同学,在看这篇文章的时候,建议结合源码来看,一步一步点进去看看,思考思考。

注意小编图中的注释,有些注释小编是写在图中截图分享的。

文章目录

  • BeanFactory是如何把BeanDefinition转换成Bean对象

    属性注入,构造注入,set注入,参数注入

  • Bean对象的生命周期

    Bean的生命周期这是一个比较形象的描述,其实①主要就是讲Bean从创建到销毁这之间的过程。②其次在Bean从创建到销毁的过程之间会穿插Spring提供给我们供我们实现接口的类的使用讲解,在说白点就是说: Spring在Bean创建的前后给我们开发者去操作的机会,而需要我们继承某些类才能实现这些功能,我们要知道是那些类。如果对以上两点你都清楚了,那么无论是谁让你在讲Bean的生命周期你就可以说是完全掌握了


一.BeanFactory是如何把BeanDefinition转换成Bean对象

前面我们说了BeanDefinition是都保存在DefaultListableBeanFactory类的beanDefinitionMap方法中的。那么我们就应该知道如果要转换bean肯定要

从这个集合中去读取BeanDefinition来进行处理。

我们看下获取Bean的方法。Bean有单例模式和原型模式。单例模式是随着Spring上下文加载完成就已经转换完成的被放在DefaultSingletonBeanRegistry的singletonObjects集合中。

而原型模式是每次加载的时候都会重新去创建一个。他俩的核心实现其实是差不多的,只不过单例是一次加载完成就放到缓存中,而原型是没有使用缓存,而是每次都去创建。为了方便我们深入研究

我们把Bean设置为原型模式和懒加载,为了方便小编第一次就进去到getBean方法里面。

开始进入

其实无论是下面那个方法,调用顺序最后都是这样调用的doGetBean()

①AbstractBeanFactory.doGetBean()

② AbstractAutowireCapableBeanFactory.createBean()

③ AbstractAutowireCapableBeanFactory.doCreateBean()

④ AbstractAutowireCapableBeanFactory.populateBean()

其中123都是实例化Bean而并不会注入其依赖的Bean,(但是排除,使用构造注入的情况)而4才真正想

这个实例中去注入依赖。同时注入通过配置文件读取的配置比如下图。

下面跟着小编的步骤来探索一下。

进入doCreateBean方法(看下图注释)

populateBean实现了注入的功能,可以从ioc中获取自己需要的依赖并注入,同时可以从配置文件中拿到你的依赖的值。

initalizeBean这个方法中是调用InitializingBean的afterPropertiesSet完成用户定义的初始化方法,但是注意初始化方法Spring中有两个

第一个就是实现InitializingBean的afterPropertiesSet,接口

第二个是xml中配置init-method。判断逻辑是先判断是否实现InitializingBean接口,其次判断init-method。如果都有都执行。

,并在前后留下了接口,供开发者对Bean做修改。

到这里当Bean的依赖都注入成功,可以返回getBean了。

二.Bean对象的生命周期

其实上面就已经把Bean的生命周期说了一大半了,除了destroy没有说,其他都讲了。下面我们专门说Bean的销毁方法

destroyBeans中有我们可以学习的东西,看完之后肯定GET到一个点!

首先小编先提一个问题!

小编想问,如果你写的程序正在运行,此时你把idea突然关了,或者是ctrl+z终止了程序,此时怎么去执行销毁呢?

好了本来小编想举几个例子,github,svn等等的钩子程序,但是篇幅太长了,就不扯了。直接上代码。

这段代码在运行时候并不会立即打印,而是在小编点击关闭程序的时候才会执行。其实就是一个hook钩子程序

现在我们在Spring的源码中在找找Spring是

正常情况和非正常情况如何销毁Bean的呢?

正常情况

调用上图步骤13



调用流程图

看到这里我们就清楚@PreDestroy 和DisposableBean接口和xml中destroy-method用户配置的销毁方法的执行顺序了。顺便在这里提一下@PostConstruct和InitializingBean接口和xml中init-method的顺序也是一样的。都是先执行注解的@PreDestroy和@PostConstruct,然后接口DisposableBean/InitializingBean,最后才是xml中用户自己配置的。

非正常情况

非正常情况其实和正常情况的调用流程一样,只是触发的时间点不一样。非正常情况是在ctrl+z或者程序异常退出的时候去执行的。使用的技术就是上面我们演示的hook钩子程序。

我们看AbstractApplicationContext中有一个钩子线程,并提供了一个注册钩子程序的方法registerShutdownHook。说到这里相信大家都明白了吧。

通过短时倒谱(Cepstrogram)计算进行时-倒频分析研究(Matlab代码实现)内容概要:本文主要介绍了一项关于短时倒谱(Cepstrogram)计算在时-倒频分析中的研究,并提供了相应的Matlab代码实现。通过短时倒谱分析方法,能够有效提取信号在时间与倒频率域的特征,适用于语音、机械振动、生物医学等领域的信号处理与故障诊断。文中阐述了倒谱分析的基本原理、短时倒谱的计算流程及其在实际工程中的应用价值,展示了如何利用Matlab进行时-倒频图的可视化与分析,帮助研究人员深入理解非平稳信号的周期性成分与谐波结构。; 适合人群:具备一定信号处理基础,熟悉Matlab编程,从事电子信息、机械工程、生物医学或通信等相关领域科研工作的研究生、工程师及科研人员。; 使用场景及目标:①掌握倒谱分析与短时倒谱的基本理论及其与傅里叶变换的关系;②学习如何用Matlab实现Cepstrogram并应用于实际信号的周期性特征提取与故障诊断;③为语音识别、机械设备状态监测、振动信号分析等研究提供技术支持与方法参考; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,先理解倒谱的基本概念再逐步实现短时倒谱分析,注意参数设置如窗长、重叠率等对结果的影响,同时可将该方法与其他时频分析方法(如STFT、小波变换)进行对比,以提升对信号特征的理解能力。
Spring的IoC容器管理Bean生命周期的方式主要涉及创建、初始化、使用和销毁等阶段。 在创建阶段,通过构造器或工厂方法创建Bean实例[^3]。接着进入属性设置阶段,为Bean的属性设置值,并处理对其他Bean的引用[^3]。 之后,将Bean实例传递给Bean后置处理器的`postProcessBeforeInitialization`方法。这个方法可以在Bean初始化之前对其进行额外处理,例如进行AOP等操作。可以通过定义实现`BeanPostProcessor`接口的类来实现这一功能,如定义`MyBeanPostProcessor`类,实现`postProcessBeforeInitialization`方法,在该方法中可以添加自定义的处理逻辑,示例代码如下: ```java package com.spring.c1; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("对"+beanName+"进行后置处理器操作(BeforeInitialization)"); return bean; } } ``` 然后,调用Bean的初始化方法`init - method`,这是开发者可以自定义的初始化逻辑。 再将Bean实例传递给Bean后置处理器的`postProcessAfterInitialization`方法,同样可以在该方法中添加自定义的处理逻辑,示例代码如下: ```java package com.spring.c1; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("对"+beanName+"进行后置处理器操作(AfterInitialization)"); return bean; } } ``` 经过上述步骤后,Bean就可以被使用了。 当容器关闭时,会调用Bean的销毁方法`destroy - method`。销毁方式有两种,一是调用bean实现的`DisposableBean`的`destroy`方法,二是调用`@Bean`设置的`destroyMethod`方法[^4]。 Spring容器使用map结构来存储对象,一般存在三级缓存,一级缓存存放成品对象,二级缓存存放半成品对象,三级缓存是一个lambda表达式,这也有助于对Bean生命周期的管理[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西魏陶渊明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值