【Spring源码】小白速通解析Spring源码,从0到1,持续更新!
Spring源码
参考资料
https://www.bilibili.com/video/BV1Tz4y1a7FM
https://www.bilibili.com/video/BV1iz4y1b75q

bean的生命周期
bean–>推断构造方法(默认是无参构造,或指定的构造方法)–>实例化成普通对象(相当于new bean)
–>进行依赖注入(bean里的属性)–>执行afterPropertiesSet()(InitializingBean的一个回调方法,同@PostConstruct)
–>初始化后是否需要AOP–>AOP–>代理对象(target=普通对象)–>把对象放入Map<beanname,bean对象>单例池
//真正创建Bean的方法protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.//封装被创建的Bean对象BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = instanceWrapper.getWrappedInstance();//获取实例化对象的类型Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// Allow post-processors to modify the merged bean definition.//调用PostProcessor后置处理器synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.//向容器中缓存单例模式的Bean对象,以防循环引用boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isDebugEnabled()) {logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}//这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.//Bean对象的初始化,依赖注入在此触发//这个exposedObject在初始化完成之后返回作为依赖注入完成后的BeanObject exposedObject = bean;try {//将Bean实例对象封装,并且Bean定义中配置的属性值赋值给实例对象populateBean(beanName, mbd, instanceWrapper);//初始化Bean对象exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}if (earlySingletonExposure) {//获取指定名称的已注册的单例模式Bean对象Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {//根据名称获取的已注册的Bean和正在实例化的Bean是同一个if (exposedObject == bean) {//当前实例化的Bean初始化完成exposedObject = earlySingletonReference;}//当前Bean依赖其他Bean,并且当发生循环引用时不允许新创建实例对象else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);//获取当前Bean所依赖的其他Beanfor (String dependentBean : dependentBeans) {//对依赖Bean进行类型检查if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.//注册完成依赖注入的Beantry {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}
//初始容器创建的Bean实例对象,为其添加BeanPostProcessor后置处理器protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {//JDK的安全机制验证权限if (System.getSecurityManager() != null) {//实现PrivilegedAction接口的匿名内部类AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {//为Bean实例对象包装相关属性,如名称,类加载器,所属容器等信息invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;//对BeanPostProcessor后置处理器的postProcessBeforeInitialization//回调方法的调用,为Bean实例初始化前做一些处理if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}//调用Bean实例对象初始化的方法,这个初始化方法是在Spring Bean定义配置//文件中通过init-method属性指定的try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}//对BeanPostProcessor后置处理器的postProcessAfterInitialization//回调方法的调用,为Bean实例初始化之后做一些处理if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}
三级缓存解决循环依赖
循环依赖
在A创建的过程中,A的属性B需要注入属性A
- singletonObjects(一级缓存)
- earlysingletonObjects(二级缓存)
- singletonFactories(三级缓存)
- private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
- 创建的A放入 Set singletonsCurrentlyInCreation(只要创建就放入set,表示bean正在初始化)
- 首先是实例化,new 普通对象,addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));为了防止循环引用,尽早持有对象的引用,第二个参数是一个lamda表达式可用来获取普通对象
- 在A填充B时,B需要注入A,判断A正在初始化,此时出现循环依赖
- 先向二级缓存里查找,在多方循环中保证创建的是都是同一个代理对象A
- 再向三级缓存里查找,没有则执行lamda获取普通对象,并且进行AOP,生成代理对象
- 放入bean到二级缓存中
- 填充其他的属性
- 进行Aop的逻辑,若是循环依赖则会提前进行Aop(step5)而不是现在
- 在二级缓存里查找,是不是已经有已经生成好的bean
- 添加到单例池
- Set中removeA,标识初始化完成
相关文章:
【Spring源码】小白速通解析Spring源码,从0到1,持续更新!
Spring源码 参考资料 https://www.bilibili.com/video/BV1Tz4y1a7FM https://www.bilibili.com/video/BV1iz4y1b75q bean的生命周期 bean–>推断构造方法(默认是无参构造,或指定的构造方法)–>实例化成普通对象(相当于ne…...
Unity 鼠标实现对物体的移动、缩放、旋转
文章目录 1. 代码2. 测试场景 1. 代码 using UnityEngine;public class ObjectManipulation : MonoBehaviour {// 缩放比例限制public float MinScale 0.2f;public float MaxScale 3.0f;// 缩放速率private float scaleRate 1f;// 新尺寸private float newScale;// 射线pri…...
67Class 的基本语法
Class 的基本语法 类的由来[constructor() 方法](https://es6.ruanyifeng.com/#docs/class#constructor() 方法)类的实例实例属性的新写法取值函数(getter)和存值函数(setter)属性表达式[Class 表达式](https://es6.ruanyifeng.c…...
企业数字化转型:无形资产占比测算(2007-2021年)
在本次数据中,参考张永珅老师的做法,利用无形资产占比测算数字化转型程度。 一、数据介绍 数据名称:企业数字化转型:无形资产占比 数据年份:2007-2021年 样本数量:32960条 数据说明:包括数…...
[centos]设置主机名
1、设置 hostnamectl set-hostname 名字 2、查看是否生效 hostnamectl status 3、打开一个新链接就可以了...
华为OD真题--新学习选址--带答案
2023华为OD统一考试(AB卷)题库清单-带答案(持续更新)or2023年华为OD真题机考题库大全-带答案(持续更新) 为了解新学期学生暴涨的问题,小乐村要建立所新学校 考虑到学生上学安全问题,需要所有学生家到学校的…...
Qt自定义对话框
介绍 自定义框主要通过对现有对话框QDialog类的派生,根据需求编写成员函数、重载信号函数、槽函数,进而实现在主QWidget中点击某个按钮后,一个对话框的弹出 流程 简化创建派生类 最后点击完成即可。 自定义ui界面,编写成员函数…...
Python 程序设计入门(018)—— format() 函数的用法详解
Python 程序设计入门(018)—— format() 函数的用法详解 目录 Python 程序设计入门(018)—— format() 函数的用法详解一、format() 函数的基本格式二、不提供 format_spec 参数三、设置字符串的对齐方式(align&#x…...
演进式架构
演进能力是一种元特征和保护其他所有架构特征的架构封装器IEEE 的软件架构定义中的41 视图模型。它关注不同角色的不同视角,将整个系统划分成了逻辑视图、开发视图、进程视图和物理视图架构师确定了可审计性、数据、安全性、性能、合法性和伸缩性是该应用的关键架构…...
OCP China Day 2023:五大社区齐聚,加速开源开放创新与落地
8月10日,2023年开放计算中国社区技术峰会(OCP China Day 2023)在北京举行。智慧时代,计算多元化、应用多样化、技术复杂化正驱动数据中心新一轮变革,开源开放社区已成为推动数据中心持续创新的重要力量,通过…...
【Linux】进程间通信之管道
【Linux】进程间通信之管道 进程间通信进程间通信目的进程间通信的方式 管道(内核维护的缓冲区)匿名管道(用于父子间进程间通信)简单使用阻塞状态读写特征非阻塞状态读写特征 匿名管道特点命名管道 匿名管道与命名管道的区别 进程…...
记录一个正则表达式
正则表达式要求如下: 至少 8 个字符; 至少包含一个小写英文字母; 至少包含一个大写英文字母; 至少包含一个数字; 至少包含一个特殊字符,特殊字符为:“!#$%^&*()-” 中的一个; 不包含2个连续…...
用于全局复根和极点查找算法的自适应网格生成器(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
修改Linux中SSH的端口
文章目录 修改Linux中SSH的端口Linux中默认的ssh端口关闭SELinux测试新端口 修改Linux中SSH的端口 Linux中默认的ssh端口 使用root用户操作 修改前先备份ssh_config cp /etc/ssh/sshd_config /etc/ssh/sshd_config_date "%Y%m%d%H%M%S"修改配置文件,找…...
Ansible从入门到精通【六】
大家好,我是早九晚十二,目前是做运维相关的工作。写博客是为了积累,希望大家一起进步! 我的主页:早九晚十二 专栏名称:Ansible从入门到精通 立志成为ansible大佬 ansible templates 模板(templa…...
国企的大数据岗位方向的分析
现如今大数据已无所不在,并且正被越来越广泛的被应用到历史、政治、科学、经济、商业甚至渗透到我们生活的方方面面中,获取的渠道也越来越便利。 今天我们就来聊一聊“大屏应用”,说到大屏就一定要聊到数据可视化,现如今…...
【MySQL--->数据类型】
文章目录 [TOC](文章目录) 一、数据类型分类二、整型类型三、bit(位)类型四、float类型五、decimal类型六、char和varchar类型1.char类型2.varchar3.char与varchar的区别 七、日期与时间类型八、enum和set 一、数据类型分类 二、整型类型 数值类型有数据存储上限,而且每个类型都…...
Ceph部署
一、存储基础 1)单机存储设备 ●DAS(直接附加存储,是直接接到计算机的主板总线上去的存储) IDE、SATA、SCSI、SAS、USB 接口的磁盘 所谓接口就是一种存储设备驱动下的磁盘设备,提供块级别的存储 ●NAS(…...
打工日记-Vue3+Ts二次封装el-table
el-table是elementUI中的表格组件,在后台把管理系统中,也是一个比较常用的组件,目前有一个比较好的开源项目ProTable,这个项目做的很好,集成了搜索,表格,分页器功能很强大。但在我的实际使用中也…...
funbox3靶场渗透笔记
funbox3靶场渗透笔记 靶机地址 https://download.vulnhub.com/funbox/Funbox3.ova 信息收集 fscan找主机ip192.168.177.199 .\fscan64.exe -h 192.168.177.0/24___ _/ _ \ ___ ___ _ __ __ _ ___| | __/ /_\/____/ __|/ __| __/ _ |/ …...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
