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

news/2024/4/26 11:39:34/文章来源:https://blog.csdn.net/giveupgivedown/article/details/129140569

目录

  • 前言
  • 一.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.luyixian.cn/news_show_72337.aspx

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

相关文章

2023/02/21 事件循环-eventloop 宏任务 微任务 讲解

1 JS是单线程 js是单线程的。也就是说&#xff0c;同一个时间只能做一件事。作为浏览器脚本语言&#xff0c;与它的用途有关。JavaScript的主要用途是和用户互动&#xff0c;以及操作DOM&#xff0c;这决定了它只能是单线程。 js是单线程的。也就是说&#xff0c;同一个时间只…

非常优秀的网站设计案例,设计师必备

厚积才能薄发&#xff0c;一个优秀的设计师的天性一定是想要获得更多网站设计灵感&#xff0c;擅于为新项目寻找创意切入点、搜索设计参考资源、最新的设计趋势。今天为大家带来了一组免费可商用的网站设计案例&#xff0c;通过这些网站设计案例&#xff0c;你可以获得&#xf…

CF707C Pythagorean Triples 题解

CF707C Pythagorean Triples 题解题目链接字面描述题面翻译题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1样例 #2样例输入 #2样例输出 #2样例 #3样例输入 #3样例输出 #3样例 #4样例输入 #4样例输出 #4样例 #5样例输入 #5样例输出 #5提示思路代码实现题目 链接 http…

华为OD机试 - 最短耗时(C++) | 附带编码思路 【2023】

刷算法题之前必看 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:https://blog.csdn.net/hihell/category_12199283.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 华为OD机试题…

算法笔记(十一)—— 并查集、KMP

并查集 支持集合快速合并 所有数据生成各自的集合&#xff0c;需要提供查询两个两素是不是属于一个集合&#xff0c;和集合合并操作&#xff0c;并查集能够在常数时间级别上对两个操作进行实现 1. 构造结构&#xff08;数据指针&#xff09;&#xff0c;将自己的指针指向自己…

事件流、事件冒泡、阻止冒泡

1、事件流 2、事件冒泡&#xff1a;从小到大 概念&#xff1a; 当一个元素的事件被触发时&#xff0c;同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡 <style> .father{width: 300px;height: 300px;background-color: pink; } .son{width:…

Zookeeper框架

Zookeeper框架概述 1.Zookeeper介绍 Zookeeper&#xff08;以下简称ZK&#xff09;是用来管理和协调其他框架的&#xff0c;很多框架需要依赖ZK&#xff08;例如Hadoop-HA&#xff0c;Kafka&#xff0c;HBase等&#xff09;ZK本身也是一个集群ZK本身也可以存数据(一般保存配置…

koa中间件的实现原理

koa中间件的实现原理如何&#xff1f;先来看一个例子。koa的执行顺序是这样的&#xff1a;const middleware asyncfunction (ctx, next) {console.log(1)await next()console.log(6) }const middleware2 asyncfunction (ctx, next) {console.log(2)await next()console.log(5…

LeetCode 535. TinyURL 的加密与解密

TinyURL 是一种 URL 简化服务&#xff0c; 比如&#xff1a;当你输入一个 URL https://leetcode.com/problems/design-tinyurl 时&#xff0c;它将返回一个简化的URL http://tinyurl.com/4e9iAk 。请你设计一个类来加密与解密 TinyURL 。 加密和解密算法如何设计和运作是没有限…

产品新说 | 指标异常?怎么做能更好配合业务变化(一)

​ 背景&#xff1a; 企业业务运营的平稳&#xff0c;常常要依靠智能运维在后方保驾护航。熟悉运维的肯定都知道&#xff0c;在智能运维中有一环是通过监控指标来判断系统、云、业务应用、网络设备等运行的是否健康&#xff0c;以便及时排障维稳后台。在指标异常检测中&#xf…

读书笔记//来自公众号(2)

非常喜欢阅读同行的文章&#xff0c;彷佛进行一场隔空交流。大家都是数据分析师&#xff0c;有许多共鸣&#xff1b;了解数据分析在不同行业的应用&#xff0c;往往很有收获。 这位朋友在零售行业、工业物联网、汽车互联网、2G电商等做个数据分析&#xff0c;有10多工作经验。…

opencv在windows下环境搭建遇到问题

文章目录debug模式下执行到cv::imshow()报内存异常qt配置opencv环境出现的问题debug模式下执行到cv::imshow()报内存异常 原因是&#xff1a;在添加静态库的时候opencv_world460.lib和opencv_world460d.lib都导入了。 在debug模式下只能导入opencv_world460d.lib动态库&#xf…

OpenGL 渲染管线与显卡可执行程序

渲染管线的六个步骤 OpenGL 渲染管线的六个步骤&#xff0c;从指定几何图元到帧缓冲区写入像素&#xff0c;图像就被 OpenGL 引擎一步步地渲染到屏幕&#xff08;FBO&#xff09;上去了。 指定几何对象 OpenGL 引擎会根据开发者的指令去绘制几何图元。OpenGL&#xff08;ES&…

IMX6ULL学习笔记(17)——工程管理

一、简介 之前我们把所有源码文件放在一个文件夹下。 这样做存在两个主要问题&#xff0c;第一&#xff0c;代码存放混乱不易阅读。第二&#xff0c;程序可移植性差。如果工程源文件达到几十、甚至数百个的时候&#xff0c;这样一股脑全部放到根目录下就会使工程显得混乱不堪。…

[JavaEE系列] 详解面试中HTTP协议HTTPS协议

文章目录HTTP不安全HTTPS中的加密算法对称加密非对称加密混合加密HTTPS中的摘要算法HTTPS中的数字证书SSL /TLS握手TCP建立连接&#xff08;三次握手&#xff09;三次握手中常见的面试题&#xff1a;TCP断开连接&#xff08;四次挥手&#xff09;四次挥手中常见的面试题&#x…

前端页面开发模块组织结构

模块组织 任何超过 1000 行的 CSS 代码,你都曾经历过这样的体验: 这个 class 到底是什么意思呢?这个 class 在哪里被使用呢?如果我创建一个 xxoo class,会造成冲突吗?Reasonable System for CSS Stylesheet Structure 的目标就是解决以上问题,它不是一个框架,而是通过…

2.5|1.3 操作系统与嵌入式操作系统概述

CPU是计算机系统的心脏&#xff0c;操作系统是计算机系统的大脑。半个世纪以来操作系统这门软件科学吸引了世界上一大群最热情、最有智慧的杰出人材&#xff0c;集中了人类现代创造性思维活动的精髓。操作系统是软件世界的万花筒、世博会&#xff0c;是软件王国中的一顶璀璨的皇…

十二、Django表单

表单 在之前的案例中&#xff0c;每次我们需要提交表单数据的时候。我们都需要去手动编辑html表单&#xff0c;根据不同的字段&#xff0c;字段名&#xff0c;进行编码。做了很多重复的部分&#xff0c;所以django提供了一个专门用来处理表单的类&#xff0c;django.forms.For…

代码随想录算法训练营第六天 |哈希表理论基础、242.有效的字母异位词、349. 两个数组的交集 、202. 快乐数、 1. 两数之和

打卡第六天&#xff0c;补昨天的卡 今日任务 哈希表理论基础242.有效的字母异位词349.两个数组的交集202.快乐数1.两数之和 哈希表理论基础 哈希表是根据关键码的值而直接进行访问的数据结构。 哈希表能解决什么问题呢? 一般哈希表都是用来快速判断一个元素是否出现集合里。 …

Tr0ll1靶机训练

信息收集 主机探测 端口扫描 21,22,80端口开放通过浏览器访问并进行指纹识别&#xff0c;并没没有发现什么有用信息 测试 观察发现21端口开放&#xff08;ftp&#xff09;尝试进行匿名登录发现其中存在一个流量文件将其下载 并将文件用wirwshark打开&#xff0c;追踪其TCP流(…