Spring如何管理Bean的生命周期呢?
我们都知道,在面试的过程中,关于 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 的垃圾回收机制销毁。
相关文章:
Spring如何管理Bean的生命周期呢?
我们都知道,在面试的过程中,关于 Spring 的面试题,那是各种各样,很多时候就会问到关于 Spring的相关问题,比如 AOP ,IOC 等等,还有就是关于 Spring 是如何管理 Bean 的生命周期的相关问题&#…...

Java网络编程:UDP通信篇
目录 UDP协议 Java中的UDP通信 DatagramSocket DatagramPacket UDP客户端-服务端代码实现 UDP协议 对于UDP协议,这里简单做一下介绍: 在TCP/IP协议簇中,用户数据报协议(UDP)是传输层的一个主要协议之一…...

HTML+CSS+JS简易计算器
HTMLCSSJS简易计算器 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>简易计算器</t…...

STM32使用ST-LINK下载程序中需要注意的几点
使用keil5的ST-link下载界面 前提是ST-LINK已经连接好,(下图中是没有连接ST-link设备),只是为了展示如何查看STlink设备是否连接的方式 下载前一定设置下载完成后自启动 这个虽然不是必须,但对立即看到新程序的现象…...

我和jetson-Nano的故事(12)——安装pytorch 以及 torchvision
在jetson nano中安装Anaconda、pytorch 以及 torchvision 1.Pytorch下载安装2.Torchvision安装 1.Pytorch下载安装 首先登录英伟达官网下载Pytorch安装包,这里以PyTorch v1.10.0为例 安装依赖库 sudo apt-get install libjpeg-dev zlib1g-dev libpython3-dev liba…...

「异步魔法:Python数据库交互的革命」(一)
Hi,我是阿佑,今天将和大家一块打开异步魔法的大门,进入Python异步编程的神秘领域,学习如何同时施展多个咒语而不需等待。了解asyncio的魔力,掌握Async SQLAlchemy和Tortoise-ORM的秘密,让你的数据库操作快如…...
探秘GPT-4o:从版本对比到技术能力的全面评价
随着人工智能技术的不断发展,自然语言处理领域的突破性技术——GPT(Generative Pre-trained Transformer)系列模型也在不断演进。最新一代的GPT-4o横空出世,引起了广泛的关注和讨论。在本文中,我们将对GPT-4o进行全面评…...
四川汇烁面试总结
自我介绍项目介绍、 目录 1.jdk和jre的区别? 2.一段代码的执行流程? 3.接口与抽象类的区别? 4.ArrayList与LinkList的区别? 5.对HashMap的理解? 6.常见的异常? 7.throw 和 throws 有什么区别? 8.…...

【小程序 按钮 表单 】
按钮 代码演示 xxx.wxml <view class"boss" hover-class"box"hover-start-time"2000"hover-stay-time"5000">测试文本<view hover-stop-propagation"true">子集</view><view>子集2</view>…...

高铁Wifi是如何接入的?
使用PC端的朋友,请将页面缩小到最小比例,阅读最佳! 在飞驰的高铁上,除了窗外一闪而过的风景,你是否好奇过,高铁Wifi信号如何连接的呢? 远动的火车可不能连接光纤吧,难道是连接的卫星…...

gitlab之docker-compose汉化离线安装
目录 概述离线资源docker-compose结束 概述 gitlab可以去 hub 上拉取最新版本,在此我选择汉化 gitlab ,版本 11.x 离线资源 想自制离线安装镜像,请稳步参考 docker镜像的导入导出 ,无兴趣的直接使用在此提供离线资源 百度网盘(链…...

【算法】dd爱转转
✨题目链接: dd爱旋转 ✨题目描述 读入一个n∗n的矩阵,对于一个矩阵有以下两种操作 1:顺时针旋180 2:关于行镜像 如 变成 给出q个操作,输出操作完的矩阵 ✨输入描述: 第一行一个数n(1≤n≤1000),表示矩阵大小 接下来n行ÿ…...

Python3 笔记:IDLE的几个基本设置
1、设置字体: Options > Configure IDLE > Fonts 2、设置文字颜色(设置高亮): Options > Configure IDLE > Highlights 3、设置背景颜色: Options > Configure IDLE > Highlights 4、设置窗口&a…...
Mysql:存储过程练习
create table stu( id int(3) primary key auto_increment, name varchar(20) not null, grade float, gender char(2)); insert into stu(name,grade,gender) values(tom,60,男),(jack,70,男),(rose,90,女),(lucy,100,…...

详解Java ThreadLocal
个人博客 详解Java ThreadLocal | iwts’s blog Java ThreadLocal ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。 TreadLocal存储模型 ThreadLocal的静态…...
Unable to parse response body for Response{requestLine=PUT
1 异常信息: Caused by: java.lang.RuntimeException: Unable to parse response body for Response{requestLinePUT /an_path_statistic_log/_doc/11?timeout1m HTTP/1.1, hosthttp://192.168.3.60:9200, responseHTTP/1.1 200 OK}at org.springframework.data.e…...
GitHub的原理及应用详解(六)
本系列文章简介: GitHub是一个基于Git版本控制系统的代码托管平台,为开发者提供了一个方便的协作和版本管理的工具。它广泛应用于软件开发项目中,包括但不限于代码托管、协作开发、版本控制、错误追踪、持续集成等方面。 GitHub的原理可以简单…...

基于PHP+MySQL组合开发的微信小程序分销商城源码系统 分销商城+积分商城+多商户 功能强大 带完整的安装代码包以及搭建教程
系统概述 在当今数字化商业时代,拥有一个强大而多功能的分销商城系统对于企业的发展至关重要。本文将重点介绍基于 PHPMySQL 组合开发的微信小程序分销商城源码系统,它融合了分销商城、积分商城和多商户等功能,不仅功能强大,还提…...

kafka-消费者组偏移量重置
文章目录 1、消费者组偏移量重置1.1、列出所有的消费者组1.2、查看 my_group1 组的详细信息1.3、获取 kafka-consumer-groups.sh 的帮助信息1.4、 偏移量重置1.5、再次查看 my_group1 组的详细信息 1、消费者组偏移量重置 1.1、列出所有的消费者组 [rootlocalhost ~]# kafka-…...

一书读懂Python全栈安全,剑指网络空间安全
写在前面 通过阅读《Python全栈安全/网络空间安全丛书》,您将能够全面而深入地理解Python全栈安全的广阔领域,从基础概念到高级应用无一遗漏。本书不仅详细解析了Python在网络安全、后端开发、数据分析及自动化等全栈领域的安全实践,还紧密贴…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...

jdbc查询mysql数据库时,出现id顺序错误的情况
我在repository中的查询语句如下所示,即传入一个List<intager>的数据,返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致,会导致返回的id是从小到大排列的,但我不希望这样。 Query("SELECT NEW com…...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...

Element-Plus:popconfirm与tooltip一起使用不生效?
你们好,我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip,产品要求是两个需要结合一起使用,也就是鼠标悬浮上去有提示文字,并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…...