深入Spring底层透析bean生命周期及循环引用的醍醐灌顶篇

news2025/2/24 3:27:30

目录

  • 前言
  • 一.Bean的生命周期
    • 1.1 Bean的实例化阶段
    • 1.2 Bean的初始化阶段(重点)
    • 1.3 Bean的完成阶段
  • 二.循环引用问题(面试常问题)
  • 三.Spring的三级缓存(重点来了)
  • 四.完整的Spring IoC整体总结

前言

本篇是接着bean的创建基本流程,后置处理器的的续写,了解本篇的Bean的生命周期需要熟悉bean创建的基本过程和后置处理器

Bean的创建基本流程:http://t.csdn.cn/9nfTE
后置处理器详解:http://t.csdn.cn/PjMYc

最后,文章部分为个人的总结与思考,如果遗漏欢迎指正或补充,感谢您的阅览,愿您终有所获


一.Bean的生命周期

先来简单回顾一下bean的实例化步骤

bean的实例化步骤总共5步

1.将bean的配置信息封装成一个BeanDefinition对象
2.把所有的BeanDefinition对象存储到beanDefinitionMap的Map集合中
3.Spring框架再对该Map进行遍历,取出每个BeanDefinition对象的配置信息,通过反射创建bean
4.创建好的Bean对象存储在一个名为singletonObjects(单例池,也在BeanFactory中维护)的Map集合中
5.当调用getBean方法最终从该Map集合中取出Bean实例对象返回


而bean的生命周期是在bean实例化后,即通过反射创建对象那时开始,到注入属性,成为一个完整的bean,最后存储到单例池中,这个过程称为bean的生命周期

bean的生命周期大致分为三个阶段:
1 Bean的实例化阶段
2 Bean的初始化阶段
3 Bean的完成阶段

下面就会对这3个阶段做详细分解


1.1 Bean的实例化阶段

Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton(单例)的,是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化


1.2 Bean的初始化阶段(重点)

Bean创建之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充、执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,Spring的注解功能等

spring高频面试题Bean的循环引用问题都是在这个阶段体现的


Spring Bean的初始化过程涉及如下几个过程:

①Bean实例的属性填充(就是通过BeanDefinition中封装的bean的属性信息set到bean里)

在这里插入图片描述

下面是BeanDefinition中封装的bean的属性位置,上图看印象更深刻

在这里插入图片描述


Bean实例属性填充几种情况

Spring在进行属性注入时,会分为如下几种情况:

  • 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;
  • 注入单向对象(比如举例,service依赖dao的注入,而dao创建不依赖service的注入,简而言之,就是dao对象是service对象的属性)引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;
  • 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题,暂时别急,下面会详细阐述解决方案。
    在这里插入图片描述

②Aware接口属性注入(当有些bean实现一些扩展接口,需要什么对象,框架就通过Aware接口规定的方法注入进去,在这里不是重点)

③BeanPostProcessor的before()方法回调(bean的后处理器的重写方法)

④InitializingBean接口的初始化方法回调

⑤自定义初始化方法init回调

⑥BeanPostProcessor的after()方法回调(bean的后处理器的重写方法)


1.3 Bean的完成阶段

经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期。


二.循环引用问题(面试常问题)

循环依赖发生时机是在Bean实例属性填充时

多个实体之间相互依赖并形成闭环的情况就叫做"循环依赖",也叫做"循环引用"

在这里插入图片描述
属性互相注入,导致无法创建完整的bean对象,上图更形象的展示了B依赖A注入,A依赖B注入的情况,结果形成闭环


循环依赖图解过程

在这里插入图片描述


三.Spring的三级缓存(重点来了)

Spring提供了三级缓存存储 完整Bean实例 和 半成品Bean实例 ,用于解决循环引用问题
在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:

public class DefaultSingletonBeanRegistry ... {
	//1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
	Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
	//2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
	Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
	//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存"
	Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}

可以看看它在源码的位置

在这里插入图片描述


三级缓存详细图解原理

下面图解给的注释很详细,按步骤来,细看就会发现是如何用三级缓存解决循环依赖的问题的,看懂了就是醍醐灌顶

在这里插入图片描述


UserService和UserDao循环依赖的过程结合上述三级缓存描述一下

  • UserService 实例化对象,但尚未初始化,将UserService存储到三级缓存;
  • UserService 属性注入,需要UserDao,从缓存中获取,没有UserDao;
  • UserDao实例化对象,但尚未初始化,将UserDao存储到到三级缓存;
  • UserDao属性注入,需要UserService,从三级缓存获取UserService,UserService从三级缓存移入二级缓存;
  • UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存;
  • UserService 注入UserDao;
  • UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存

当然,如果有兴趣去底层翻阅源码查看其中调用过程和实习方式可以根据黑马的调用流程图来翻阅,避免迷失在源码中,反正翻源码时务必目的明确,别贪。
三级缓存源码调用流程图:https://pan.baidu.com/s/1jwruaz9NmFN9sFHf6Ksrqw?pwd=sohp
提取码:sohp


四.完整的Spring IoC整体总结

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人工智能详细笔记 :卷积神经网络(CNN)

卷积神经网络和深度学习1.卷积神经网络的结构2.卷积神经网络的卷积运算3.卷积神经网络中的关键技术BP神经网络存在的问题&#xff1a; 输入类型限制&#xff1a;BP神经网络以数值作为输入。如果需要计算图像相关的信息的话&#xff0c;首先需要从图像中提取特征。隐层数量限制…

直播预告 | 嵌入式BI如何将数据分析真正融入业务流程

在信息化高速发展的今天&#xff0c;数据成为企业最有价值的资产之一。而数据本身很难直接传递有价值的信息&#xff0c;只有通过对数据进行挖掘、分析&#xff0c;才能让数据真正成为生产力。 商业智能&#xff08;BI&#xff09;应运而生&#xff0c;可以帮助企业更好地从数…

ASP.NET MVC | 简介

目录 前提 1.教程 2.MVC 编程模式 最后 前提 在学习学过很多课程&#xff0c;但是最主要学的还是ASP.NET MVC这门课程&#xff0c;工作也是用的ASP.NET MVC&#xff0c;所以写一点ASP.NET MVC的东西&#xff0c;大家可以来看看&#xff0c;我自己不会的时候也不用找别的地方…

django项目实战六(django+bootstrap实现增删改查)进阶优化modelform类与视图

目录 一、将视图里面的modelform类分离出去 二、按模块迁移视图 1、新建views视图文件夹 2、views下新建对应模块文件&#xff0c;并从views.py当中迁移代码 三、删除views.py 四、修改url路由 接上一篇《django项目实战五&#xff08;djangobootstrap实现增删改查&#xf…

数据结构-考研难点代码突破(C++实现树型查找 - 平衡二叉树(AVL树)的基本操作(增删))

文章目录1. 平衡二叉树的概念AVL树的插入AVL树查找效率AVL树的删除&#xff08;了解&#xff09;2. C代码3. 考研数据结构代码仓库1. 平衡二叉树的概念 二叉搜索树虽然可以提高搜索效率&#xff0c;但如果数据接近有序的话搜索二叉树的效率退化为链表了。为了解决这个问题&…

跨境群店安全运营神器—超级浏览器

有点跨境电商经验的跨境人都知道&#xff0c;物理隔离是比较安全稳妥的防关联办法。但是多台电脑多条网络的办公方式&#xff0c;不仅设备成本高&#xff0c;人员的费用也高得吓人。后来大家开始使用VPS来防关联。VPS是一种虚拟专用服务器&#xff0c;它是一种将一台服务器分割…

企业微信机器人发送消息

前言 随着科技的发展,各企业公司的业务不断发展,那么就需要强有力的沟通软件,其中企业微信、钉钉的能力得到了大众的认可,今天这篇文章就讲其中的一个功能-调用企业微信机器人(下文简称应用)进行消息传递。它的好处有哪些呢?自然是可以让相关人员及时追踪任务进度。 一、…

记住这12个要点,你也能打造出让HR和技术主管前一亮的前端简历

第一篇章&#xff1a;吸引HR 如果你想在众多简历中脱颖而出&#xff0c;需要注意以下几点&#xff1a; 1、突出你的亮点&#xff1a; 给你的简历一个吸引人的文件命名和头部&#xff0c;突出你的关键技能和经验。 2、采用简洁的语言&#xff1a; 用简单易懂的语言来描述你的…

JavaScript-XHR-深入理解

JavaScript-XHR-深入理解1. XHR(Asynchronous JavaScript And XML)初始1.1. xhr request demo1.2. status of XHRHttpRequest1.3. send synchronous request by xhr1.4. onload监听数据加载完成1.5. http status code1.6. get/post request with josn/form/urlcoded1.7. encaps…

mysql和sqlserver查询数据库表的数量的方法

一、mysql查询数据库表的数量 1、查询mysql下所有数据库表的数量 SELECT COUNT(*) TABLES, table_schema FROM information_schema.TABLES GROUP BY table_schema; 2、查询指定数据库的表的数量 SELECT COUNT(*) TABLES, table_schema FROM information_schema.TABLES WHER…

LeetCode第494题-目标和-python实现-图解思路与手撕代码

LeetCode第494题-目标和-python实现-图解思路与手撕代码 文章目录一、题目描述二、解题思路与代码实现1.解题思路2.代码实现总结一、题目描述 二、解题思路与代码实现 1.解题思路 这道题可以进行递归&#xff0c;遍历数组&#xff0c;对于当前这个数字&#xff0c;要么加上要…

Revit项目浏览器的标准设置应用和快速视图样板?

一、Revit项目浏览器的标准设置应用 设计院阶段的BIM应用&#xff0c;主要是Revit出施工图方面&#xff0c;需要涉及到很多标准的制定方面的问题&#xff0c;而且这个标准不仅仅是一个命名标准&#xff0c;还有很多的符合本院的出图标准等等&#xff0c;本期就不做详细讨论&…

【论文阅读】SCRFD: Sample and Computation 重分配的高效人脸检测

原始题目Sample and Computation Redistribution for Efficient Face Detection中文名称采样和计算 重分配的 高效人脸检测发表时间2021年5月10日平台ICLR-2022来源Imperial College&#xff0c; InsightFace文章链接https://arxiv.org/pdf/2105.04714.pdf开源代码官方实现&…

重压之下,特斯拉并不心甘情愿地召回FSD

/ 导读 /近日&#xff0c;美国国家公路交通安全管理局&#xff08;NHTSA&#xff09;宣布&#xff0c;其将召回近37万辆已安装或待安装全自动驾驶测试版&#xff08;FSD Beta&#xff09;的汽车。其实早在今年1月份的时候&#xff0c;NHTSA就要求特斯拉提交召回申请。而特斯拉在…

LabVIEW快速创建事件插件

LabVIEW快速创建事件插件此插件包含在LabVIEW2018及更高版本中。如果使用的是LabVIEW2017或更早版本&#xff0c;则只需从此处下载并安装它。在控件和控制终端上添加新的“创建>事件结构”&#xff1a;选择此选项将在控件上为指定事件配置新的事件结构&#xff1a;一些附加说…

jupyter使用指北:如何打开.ipynb文件|修改jupyter notebook的默认路径|在jupyter按照包

文章目录打开.ipynb文件、修改jupyter的默认路径笨办法好办法用jupyter notebook直接安装包运行代码打开.ipynb文件、修改jupyter的默认路径 比如&#xff0c;在该目录下有一个.ipynb文件&#xff0c;想用jupyter notebook直接打开&#xff1a; 笨办法 先进入jupyter再把文…

FFMPEG自学二 ⾳频编码实战

一、FFmpeg编码流程二、流程关键函数avcodec_find_encoder&#xff1a;根据指定的AVCodecID查找注册的编码器。 avcodec_alloc_context3&#xff1a;为AVCodecContext分配内存。 avcodec_open2&#xff1a;打开编码器。 avcodec_send_frame&#xff1a;将AVFrame⾮压缩数据给…

LVGL Styles

LVGL StylesGet started按钮添加标签按钮添加风格滑动条值显示StylesSize stylesBackground stylesBorder stylesOutline stylesShadow stylesImage stylesArc stylesText stylesLine stylesGet started 按钮添加标签 /*** brief 按钮事件回调函数* param e */ void btn_eve…

【Python实战】一大波高颜值主播来袭:快看,某网站颜值排名,为了这个排名我可是大费周章啦,第一名不亏是你...(人脸检测+爬虫实战)

导语 民间一直有个传闻......「听说某站的小哥哥小姐姐颜值都很高哦&#xff01;」 &#xff08;不是颜值高才能加入&#xff0c;是优秀的人恰好颜值高&#xff09; 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝白嫖源码福利&#xff0c;请移步至CSDN社区或文末…

Qt C++ 自定义仪表盘控件03

简介仪表盘是工控领域不可缺少的一类软件UI元素&#xff0c;通常出现在各类电子看板软件上&#xff0c;以及一些高级的上位机软件界面上&#xff0c;目的是将繁杂的数据转化为可视化的图表能大幅提高后台管理效率。本文分享了几个经典常用的仪表盘控件&#xff0c;在项目中可以…