Spring如何管理Bean的生命周期呢?

news/2024/7/20 18:34:14/文章来源:https://blog.csdn.net/H_Sino/article/details/139256023

我们都知道,在面试的过程中,关于 Spring 的面试题,那是各种各样,很多时候就会问到关于 Spring的相关问题,比如 AOP ,IOC 等等,还有就是关于 Spring 是如何管理 Bean 的生命周期的相关问题,今天了不起就来和大家一起看看 Spring 是如何管理 Bean 的生命周期的。

源码分析

BeanFactory

其实我们对于这个 Spring 管理 Bean 的生命周期有时候并不需要我们去大篇幅的去背诵某块的内容,我们需要的就是学会看源代码,比如源代码中的注释部分,当我们看到这注释部分的时候,很大程度上能够帮助我们理解源码的含义。

BeanFactory是Spring框架中的一个接口,它是一个工厂类,用来创建和管理Spring中的Bean对象。

我们看源码中的注释

* <p>Bean factory implementations should support the standard bean lifecycle interfaces* as far as possible. The full set of initialization methods and their standard order is:

这句话直接翻译就是 Bean Factory 实现类应该尽可能的支持标准的生命周期接口。注释的下半段内容,就是描述的 Bean 生命周期的相关内容了。所以源码里面的注释需要我们及时的去看一下,虽然都是纯英文的,但是能读出个大概得内容,再去看源码的话,至少知道它是干嘛的方法。

Bean 的生命周期

我们在了解他如何管理的时候,我们得先知道这个 Bean 的生命周期都有哪几个阶段,知道了阶段,我们再来看它的实现。

我们先总结:

Bean 的生命周期可以总结为如下的几个阶段,

1. Bean的实例化阶段

2. Bean的设置属性阶段

3. Bean的 初始化阶段

4. Bean的销毁阶段

也有些人会细分实例化阶段,就是把实例化拆分成两部分,第一部分是注册阶段,第二部分是实例化阶段,其实区别不大。

Bean实例化阶段

在Spring框架中,Bean的实例化是一个核心过程,它涉及了多个步骤以确保Bean能够正确地被创建并注入到应用上下文中。

Bean定义注册:

  • 首先,你需要在Spring的配置文件(如XML配置文件或Java配置类)中定义Bean。这包括指定Bean的类名、作用域、初始化方法、销毁方法以及可能的依赖关系等。

  • Spring容器会读取这些配置,并将Bean定义信息存储在其内部的数据结构中,通常是BeanDefinition对象。

实例化前的准备:

  • 在实例化Bean之前,Spring会进行一些准备工作,如解析Bean定义中的属性、检查依赖关系等。

  • 如果Bean定义中引用了其他Bean,Spring会尝试先解析并实例化这些依赖Bean。

实例化:

  • 实例化是创建Bean对象的过程。Spring提供了多种实例化Bean的方式:

    • 构造器实例化:通过调用Bean的构造方法来创建实例。你可以在配置文件中指定要使用的构造方法,并提供相应的参数。

    • 静态工厂方法实例化:通过调用静态工厂方法来创建Bean实例。你需要在配置文件中指定工厂类的类名和工厂方法的名称。

    • 实例工厂方法实例化:首先实例化一个工厂Bean,然后调用该工厂Bean的某个非静态方法来创建目标Bean实例。

    • 默认构造器实例化:如果Bean定义中没有指定其他实例化方式,并且Bean类有一个无参构造器,那么Spring将使用默认构造器来实例化Bean。

  • 实例化完成后,你得到的是一个原始的对象,它还没有进行任何属性注入或初始化。

属性注入:

  • 在Bean实例化之后,Spring会进行属性注入(也称为依赖注入)。这包括将Bean定义中指定的属性值或对其他Bean的引用注入到Bean的相应属性中。

  • Spring支持多种属性注入方式,如基于字段的注入、基于setter方法的注入和基于构造器的注入等。

BeanPostProcessor处理:

在Bean的属性注入完成后,但Bean的初始化方法执行之前,Spring会调用已注册的BeanPostProcessor接口的postProcessBeforeInitialization方法。这是一个可选的步骤,你可以通过实现该接口并注册相应的BeanPostProcessor来在Bean初始化前后执行自定义的逻辑。

初始化:

  • 接下来,Spring会调用Bean定义中指定的初始化方法(如果有的话)。这通常是在Bean类中定义的某个方法,并用特定的注解(如@PostConstruct)或XML配置中的元素的init-method属性来指定。

  • 初始化方法是Bean在准备好接受请求之前进行必要设置或执行特定任务的地方。

BeanPostProcessor再处理:

在Bean初始化方法执行之后,Spring会再次调用已注册的BeanPostProcessor接口的postProcessAfterInitialization方法。这是另一个可选的步骤,你可以在这里执行一些清理或后处理操作。

Bean就绪:

经过上述步骤后,Bean就已经被完全创建并初始化了。现在它可以被应用上下文中的其他组件使用或注入到其他Bean中。

到这里,我们的实例化就说完了,记下来看第二阶段。

Bean的设置属性阶段

Bean的设置属性阶段(也称为属性注入或依赖注入)是Bean生命周期中的一个重要环节。这个阶段发生在Spring容器创建Bean的实例之后,但在Bean被实际使用之前。

  • 当Spring容器创建一个Bean的实例后,它会检查该Bean是否有需要注入的属性。这些属性可能是其他的Bean、基本数据类型、集合、Map等。

  • Spring会查找与这些属性对应的配置信息(可能是XML中的标签、注解中的值或其他配置方式),并将它们注入到Bean的相应字段或setter方法中。

注入方式:

  • 字段注入:通过直接在字段上使用@Autowired或其他相关注解来实现。但请注意,字段注入在某些情况下可能导致测试困难或难以遵循良好的封装原则。

  • 构造函数注入:在构造函数参数上使用@Autowired或其他相关注解。这是推荐的方式之一,因为它确保了Bean在创建时就已经拥有所有必需的依赖项,并且这些依赖项是不可变的。

  • setter方法注入:在setter方法上使用@Autowired或其他相关注解。这种方式允许Bean在创建后的某个时间点接收其依赖项。

既然我们已经把这个属性设置完毕了,那么就要开始后进行初始化阶段了。

Bean 的初始化

  • Bean Aware接口回调

  • Bean初始化前操作

  • Bean初始化操作

  • Bean初始化后操作

  • Bean初始化完成操作

BeanAware接口回调

  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) {((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}}

Bean初始化前操作

  @Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {result = beanProcessor.postProcessBeforeInitialization(result, beanName);if (result == null) {return result;}}return result;
}

Bean初始化操作

调用InitializingBean接口的afterPropertiesSet方法 调用定义bean的时候指定的初始化方法。

 public interface InitializingBean {/*** Invoked by the containing {@code BeanFactory} after it has set all bean properties* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.* <p>This method allows the bean instance to perform validation of its overall* configuration and final initialization when all bean properties have been set.* @throws Exception in the event of misconfiguration (such as failure to set an* essential property) or if initialization fails for any other reason*/void afterPropertiesSet() throws Exception;} 

Bean初始化后阶段

 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}

Bean初始化完成操作

public interface SmartInitializingSingleton {/*** Invoked right at the end of the singleton pre-instantiation phase,* with a guarantee that all regular singleton beans have been created* already. {@link ListableBeanFactory#getBeansOfType} calls within* this method won't trigger accidental side effects during bootstrap.* <p><b>NOTE:</b> This callback won't be triggered for singleton beans* lazily initialized on demand after {@link BeanFactory} bootstrap,* and not for any other bean scope either. Carefully use it for beans* with the intended bootstrap semantics only.*/void afterSingletonsInstantiated();}

当我们完成了初始化之后,使用完成,最后 Bean 就要走到销毁阶段了。

Bean 的销毁

 @Overridepublic void destroyBean(Object existingBean) {new DisposableBeanAdapter(existingBean, getBeanPostProcessorCache().destructionAware, getAccessControlContext()).destroy();}

这里需要注意的是

  • 当容器关闭时,或者当单例 Bean 的作用域结束时,Spring 会销毁 Bean 的实例。

  • 对于非单例 Bean(如 prototype 作用域的 Bean),它们会在每次请求时创建,并在不再需要时由 Java 的垃圾回收机制销毁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1052667.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OneForall工具的下载安装和使用(Windows和Linux)

目录 OneForall的介绍 OneForall的下载 OneForall的安装 安装要求 安装步骤&#xff08;git 版&#xff09; 安装&#xff08;kali&#xff09; OneForall的使用命令 在Windows 在Linux&#xff08;kali&#xff09; OneForall的结果说明 免责声明 本文所提供的文字和…

databricks~Unity Catalog

Unity Catalog hierarchy 包含了用户授权管理信息和元数据信息 workspace with unity catalog hierarchy unity metastore Ref: https://www.youtube.com/playlist?listPLY-V_O-O7h4fwcHcXgkR_zTLvddvE_GfC

逆向基础:软件手动脱壳技术入门

这里整合了一下之前自己学习软件手工脱壳的一些笔记和脱文&#xff0c;希望能给新学软件逆向和脱壳的童鞋们一点帮助。 1 一些概念 1.1 加壳 加壳的全称应该是可执行程序资源压缩&#xff0c;是保护文件的常用手段。加壳过的程序可以直接运行&#xff0c;但是不能查看源代码…

内网权限提升

打点进入内网中&#xff0c;权限一般为 web 服务的权限 1、什么是提权 一般一来说是低权限用户去申请高权限用户&#xff0c;可以是&#xff08;配置不当、溢出类漏洞&#xff08;历史漏洞&#xff09;、本地漏洞&#xff09; 2、常见用户分类 windows&#xff1a; 本地登录…

神奇动物在哪里?斯洛文尼亚旅游之野生动物寻踪

不仅拥有优美动人的自然风光&#xff0c;斯洛文尼亚还以其丰富的生物多样性而闻名。得益于国家对大自然开展的保护工作&#xff0c;斯洛文尼亚超过三分之一的国土面积都被规划为保护区&#xff0c;拥有约1.5万种动物和6000种植物&#xff0c;其中不乏众多特有、稀有和濒危动植物…

[数智人文实战] 02.舆情分析之词云可视化、文本聚类和LDA主题模型文本挖掘

【数智人文与文本挖掘】知识星球建立且正式运营,欢迎新老博友和朋友加入,一起分享更多数智人文知识和交流进步。该星球计划每周至少分享7个资源或文章,包括数智人文、文本挖掘、人工智能、大数据分析和图书情报的技术文章、代码及资源。同时,欢迎进入星球的朋友咨询我图情和…

图像处理之计算物体的方向(C++)

图像处理之计算物体的方向&#xff08;C&#xff09; 文章目录 图像处理之计算物体的方向&#xff08;C&#xff09;前言一、PCA获取物体主要方向1.原理2.代码实现 二、Hu矩获取物体主要方向1.原理2.代码实现 总结 前言 在图像处理中&#xff0c;物体的方向&#xff08;倾斜角…

基于springboot+vue的班级综合测评管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

OpenBMC相关的网站

openbmc官方网站 https://github.com/openbmchttps://github.com/openbmc Dashboard [Jenkins]https://jenkins.openbmc.org/ https://gerrit.openbmc.org/Gerrit Code Reviewhttps://gerrit.openbmc.org/ Searchhttps://grok.openbmc.org/ openbmc参考网站 https://www.c…

计算机组成原理易混淆知识点总结(持续更新)

目录 1.机器字长&#xff0c;存储字长与指令字长 2.指令周期,机器周期,时钟周期 3.CPI,IPS,MIPS 4.翻译程序和汇编程序 5.计算机体系结构和计算机组成的区别和联系 6.基准程序执行得越快说明机器的性能越好吗? 1.机器字长&#xff0c;存储字长与指令字长 不同的机器三者…

Git-01

Git是一个免费且开源的分布式版本控制系统&#xff0c;它可以跟踪文件的修改、记录变更的历史&#xff0c;并且在多人协作开发中提供了强大的工具和功能。 Git最初是由Linus Torvalds开发的&#xff0c;用于Linux内核的开发&#xff0c;现在已经成为了广泛使用的版本控制系统&a…

Java 类加载机制解密一探到底

类加载是 Java 程序在运行期执行之前的重要环节&#xff0c;它决定着程序的运行效率和稳定性。本文将为您深入剖析 Java 类加载机制的整个生命周期&#xff0c;揭开神秘面纱&#xff0c;让您彻底掌握这一核心知识点。 一、类的生命周期概述 类的生命周期在Java中指的是从类被加…

【Linux 网络】网络基础(三)(数据链路层协议:以太网协议、ARP 协议)

一、以太网 两个不同局域网的主机传递数据并不是直接传递的&#xff0c;而是通过路由器 “一跳一跳” 的传递过去。 跨网络传输的本质&#xff1a;由无数个局域网&#xff08;子网&#xff09;转发的结果。 所以&#xff0c;要理解数据跨网络转发原理就要先理解一个局域网中数…

深度解析Nginx配置文件:从全局块到upstream块的探索之旅

Nginx配置文件的简介 在浩瀚的互联网世界中&#xff0c;Nginx就如同一座大型交通枢纽&#xff0c;将访问者的请求精准地引导到正确的服务终点。而这一切&#xff0c;都离不开一个神秘而重要的角色——Nginx配置文件。这个文件&#xff0c;就像是一份详尽的路线图&#xff0c;为…

深度学习模型在OCR中的可解释性问题与提升探讨

摘要&#xff1a; 随着深度学习技术在光学字符识别&#xff08;OCR&#xff09;领域的广泛应用&#xff0c;人们对深度学习模型的可解释性问题日益关注。本文将探讨OCR中深度学习模型的可解释性概念及其作用&#xff0c;以及如何提高可解释性&#xff0c;使其在实际应用中更可…

创新力作 焕新首发丨捷顺科技·捷曜系列智慧停车新品全新上市

2024捷顺科技智慧停车全家族新品全面上市 全新外观、全新特性、全新体验 新控制机、新道闸、新超眸相机... 每款新品都有哪些功能亮点 带您一探究竟

【跟着例子学MySQL】 补充内容 -- 主外键和索引

文章目录 前言回顾主键外键索引未完待续 前言 举例子&#xff0c;是最简单有效的学习方法。本系列文章以一个贯穿始终的场景&#xff0c;结合多个实例讲解MySQL的基本用法。 ❔ 为什么要写这个系列&#xff1f; 模仿是最好的老师&#xff0c;实践是检验成果的方法。本系列以实…

机械臂与Realsense D435 相机的手眼标定ROS包

本教程主要介绍机械臂与 Realsense D435 相机手眼标定的配置及方法。 系统&#xff1a;Ubuntu 20.0.4 ◼ ROS&#xff1a;Noetic ◼ OpenCV 库&#xff1a;OpenCV 4.2.0 ◼ Realsense D435&#xff1a;librealsense sdk&#xff08;2.50.0&#xff09;、realsense-ros 功能包&…

【quarkus系列】构建可执行文件native image

目录 序言为什么选择 Quarkus Native Image&#xff1f;性能优势便捷的云原生部署 搭建项目构建可执行文件方式一&#xff1a;配置GraalVM方式二&#xff1a;容器运行错误示例构建过程分析 创建docker镜像基于可执行文件命令式构建基于dockerfile构建方式一&#xff1a;构建mic…

“提升人工智能大模型智能:策略与挑战“

文章目录 每日一句正能量前言算法创新数据质量与多样性模型架构优化后记 每日一句正能量 失败时可以称为人生财富&#xff0c;成功时可以称为财富人生。 前言 随着人工智能技术的飞速发展&#xff0c;大模型已经成为推动多个领域创新的关键力量。从自然语言处理到图像识别&…