| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 浅谈Spring中Bean的生命周期 -> 正文阅读 |
|
[Java知识库]浅谈Spring中Bean的生命周期 |
文章目录1、基本概念你只需要明白Bean生命周期的执行逻辑即可,不需要死磕对应的流程步骤及流程名字,希望本文对你有帮助。 在初学Java时,我们需要new一个类,即可得到一个对象。学到框架时,我们只需要将类注册到Spring容器中,即可得到一个对象。 本文主要讲述Spring中将一个类注册到Spring容器中的关键步骤,外界称它为Bean的生命周期。我将Spring的生命周期分为实例化前(扩展)、实例化中(实例化对象,走构造方法)、实例化后(属性填充 + 扩展)、初始化前前(完成部分属性回填)、初始化前(扩展)、初始化中(完善部分属性值)、初始化后(扩展),共7步 单就实例化和初始化两个词语的概念,一定要和JVM规范中的实例化和初始化区分开。JVM规范中类是先进行初始化,再进行实例化。而Spring中是先进行实例化,再进行初始化。Spring中Bean的实例化包含了JVM规范中的初始化和实例化。我们可以通过构造方法去观察,JVM中构造方法属于JVM规范中的实例化步骤,在Spring中Bean的生命周期步骤属于实例化步骤。当然你还可以通过静态代码块进行测试,在JVM中静态代码块属于初始化步骤,在Spring中Bean的生命周期中,处在实例化前和实例化后之间。 2、生命周期流程图
3、源码与功能分析3.1、实例化前
根据最后两张图我们可以发现,applyBeanPostProcessorsBeforeInstantiation方法会去遍历beanPostProcessors集合,然后强转为BeanPostProcess接口(Bean的后置处理器)的子接口,最后再调用接口对应的postProcessBeforeInstantiation方法,该方法默认返回为null。该返回值就间接影响了我们第二步中的返回值,我们的程序究竟是继续完成Bean对象的实例化步骤,还是直接跳转到初始化后的步骤。 总结:
3.2、实例化
3.1、实例化方法完成前:instanceWrapper为null 3.2、实例化方法完成后:instanceWrapper是我们的目标对象 根据 这三步,我们可以得出结论,createBeanInstance方法,能够实例化出我们的对象(属性还没有具体的值)在我们实例化Bean的操作完成后,会将结果赋值给instanceWrapper变量。 根据截图我们也不难发现,instanceWrapper变量可以当作是我们实例化出来对象的封装体。想要拿到我们期望创建的Bean对象,调用getWrappedClass方法即可。 总结:
3.3、实例化后
与实例化前相同,实例化后也有相同的操作,执行的流程和实例化前大体相同,这里就不再赘述。如果你足够细心,在前面展示实例化前接口截图的时候你就应该已经发现,实例化前和实例化后的操作存在某种共性。不信的话,我让你再看一遍这个接口。
我们可以看到,由于User对象内部依赖了另一个对象Cat,所以当我们在调试代码的时候,会发现,Spring会先去找Cat对象,即去处理Cat的生命周期,当Cat的生命周期执行完成之后才会来继续完成我们User对象的实例化后操作。因为这一步涉及属性的填充,Spring要先去获取我们需要填充的属性Cat,继而完成对当前对象User的属性填充,执行完该步骤,对象的赋值操作也就完成了。
总结:
3.4、初始化前前
总结:
3.5、初始化前、中、后
当熟悉了实例化前后的操作,我们会发现初始化前中后的处理操作都差不多,步骤都可以分为这几步
4、核心接口的简单代码实现4.1、简单实现spring容器启动类:
配置类:
实体类:
按照前面的分析,我的打印结果应该的顺序是123…可测试结果真的是这样吗? 测试结果: 根据测试结果发现,我们会先执行第二步、第四步、第六步,也就是实例化中、初始化前前、初始化中这三步.对应的属性赋值也测试正确,最后开始遍历BeanPostProcessor集合,依次执行剩下的步骤。说好的顺序执行呢?代码逻辑没错呀。 于是我又开始了新的思考,通过观察我发现了一个奇怪的点:我们的student对象呢?理论上说,哪怕是不顺序执行,你起码要给我执行一次呀,可是根本一次也没有。这又是为什么呢,把自己屏蔽呢? 于是我又开始了接下来的一个新测试 4.2、简单再实现1、掉Student类中的InstantiationAwareBeanPostProcessor接口,当然对应的方法也要去掉 2、新建一个Teacher类
3、再次测试 巧了,这不就是我们想要的结果,按照顺序打印。 前面多余的测试结果,我们只需要在对应的代码中添加判断即可准确的定位到我们想要的student对象。 4.3、结论至此,对于Spring的生命周期我们能否有新的理解? 除了上面的代码顺序理解以外。我们还可以将这些方法分为自身操作和集中操作两部分。 集中操作:InstantiationAwareBeanPostProcessor接口(4) 单独操作:InitializingBean接口、Aware接口的子接口以及构造方法(1+1+1) 如果这样分类,其实解决了我最开始的看源码逻辑时的一个疑惑。不知道你有没有注意,我们在调用实例化前后、初始化前后方法时,都是去遍历BeanPostProcessor集合,但执行其他方法的时候却是单独的一条线。反正我最开始是有这个疑问。那么 在一次完整Bean的生命周期过程中,它会依次完成实例化和初始化的步骤(本文分类7步)。但在这个过程中,处理实例化前后、初始化前后流程时,会调用所有实现了BeanPostProcessor接口的方法,处理相应的逻辑;处理实例化中、初始化前前、初始化中的过程,则为每个实体单独的处理操作。 如果想要让集中操作和单独操作能体现在一个类上,那么就需要使用不同的类来处理(一个类同时实现两个接口无法达到对应的效果),Bean在处理与属性相关的操作时单独操作,在处理逻辑相关时集中处理,貌似又有那么一点分层的味道。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年3日历 | -2025/3/4 1:56:27- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |