【Spring源码】小白速通解析Spring源码,从0到1,持续更新!

news2024/12/25 8:54:37

Spring源码

参考资料

https://www.bilibili.com/video/BV1Tz4y1a7FM
https://www.bilibili.com/video/BV1iz4y1b75q

image-20230727230632443

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在初始化完成之后返回作为依赖注入完成后的Bean
		Object 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所依赖的其他Bean
					for (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.
		//注册完成依赖注入的Bean
		try {
			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);
  1. 创建的A放入 Set singletonsCurrentlyInCreation(只要创建就放入set,表示bean正在初始化)
  2. 首先是实例化,new 普通对象,addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));为了防止循环引用,尽早持有对象的引用,第二个参数是一个lamda表达式可用来获取普通对象
  3. 在A填充B时,B需要注入A,判断A正在初始化,此时出现循环依赖
  4. 先向二级缓存里查找,在多方循环中保证创建的是都是同一个代理对象A
  5. 再向三级缓存里查找,没有则执行lamda获取普通对象,并且进行AOP,生成代理对象
  6. 放入bean到二级缓存中
  7. 填充其他的属性
  8. 进行Aop的逻辑,若是循环依赖则会提前进行Aop(step5)而不是现在
  9. 在二级缓存里查找,是不是已经有已经生成好的bean
  10. 添加到单例池
  11. Set中removeA,标识初始化完成

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

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

相关文章

【Vue3】Vue3 UI 框架 | Element Plus —— 创建并优化表单

安装 # NPM $ npm install element-plus --save // 或者&#xff08;下载慢切换国内镜像&#xff09; $ npm install element-plus -S// 可以选择性安装 less npm install less less-loader -D // 可以选择性配置 自动联想src目录Element Plus 的引入和注入 main.ts import…

S7-200 Smart 的多种端口及通讯方式

每个S7-200 SMART CPU都提供一个以太网端口和一个RS485端口(端口0)&#xff0c;标准型CPU额外支持SB CM01信号板(端口1)&#xff0c;信号板可通过STEP 7-Micro/WIN SMART软件组态为RS232通信端口或RS485通信端口。 CPU 通信端口引脚分配 1.S7-200 SMART CPU 集成的 RS485 通信…

数据结构入门 — 时间复杂度、空间复杂度

前言 数据结构_空间复杂度_时间复杂度讲解_常见复杂度对比 本文介绍数据结构中的时间复杂度和空间复杂度 ***文章末尾&#xff0c;博主进行了概要总结&#xff0c;可以直接看总结部分*** 博主博客链接&#xff1a;https://blog.csdn.net/m0_74014525 点点关注&#xff0c;后期…

防静电实时监控系统具有哪些功能

防静电实时监控系统是一种用于监测、检测和控制静电产生和积累的系统。它通过使用各种传感器和仪器&#xff0c;实时监测环境中的静电情况&#xff0c;并及时采取措施来防止静电危害和事故的发生。 防静电实时监控系统通常具有以下功能&#xff1a; 1. 传感器监测&#xff1a;…

Day13 04-Linux的虚拟机克隆-scp命令-ssh免登录-crontab定时器及时间同步操作

文章目录 第五章 多虚拟机的操作5.1 虚拟机克隆【掌握】5.1.1 克隆前的准备工作5.1.2. 修改IP地址5.1.3. 修改主机名5.1.4. 修改域名映射文件5.1.5. 虚拟机之间通信5.1.6. 流程总结 5.2. scp命令【重点】5.2.1. 命令格式5.2.2. 小技巧 5.3. ssh免密登录【重点】5.3.1. ssh的简介…

约数之和(质因子分解)

思路&#xff1a; &#xff08;1&#xff09;由数论基本定理&#xff0c;任何一个正整数x都能写作&#xff0c;其中p1,p2..pk为x的质因子。 &#xff08;2&#xff09; 由此可以推断&#xff0c;要求一个数约数的和&#xff0c;注意到约数就是p1,p2...pk的一种组合&#xff0…

Netty:ByteBuf类型转化

说明 io.netty.buffer.ByteBuf经常需要跟其它类型互相转化&#xff0c;例如ByteBuf类型作为Object类型函数参数传递&#xff0c;函数内部处理时将Object转换为ByteBuf。 代码示例 ByteBuf和Object类型互转 package com.thb;import io.netty.buffer.ByteBuf; import io.net…

【Java转Go】快速上手学习笔记(一)之环境安装篇

前言 前两天开始学习Go&#xff0c;需要写篇笔记记录总结一下。 Go它也是可以做web开发的&#xff0c;就像Java一样&#xff0c;做JavaWeb项目&#xff0c;Go也可以做GoWeb项目。当然Go的作用用处肯定不止这个&#xff0c;还有很多&#xff0c;只是因为我目前的话&#xff0c…

python中两个数据框之间的遍历

1.输入文件1 文件1&#xff1a;第一列是基因名字&#xff0c;列2&#xff1a;外显子起始位置&#xff0c;列3&#xff1a;外显子终止位置&#xff0c;列4&#xff1a;外显子的序号 2.输入文件2&#xff1a; 备注&#xff1a;列1&#xff1a;基因id&#xff1b;列2&#xff1a;…

浅谈早期基于模板匹配的OCR的原理

基于模板匹配的概念是一种早期的字符识别方法&#xff0c;它基于事先准备好的字符模板库来与待识别字符进行比较和匹配。其原理如下&#xff1a; 1. 字符模板库准备&#xff1a;首先&#xff0c;针对每个可能出现的字符&#xff0c;制作一个对应的字符模板。这些模板可以手工创…

Milvus Cloud向量数据库或率先在垂直领域体现价值

从市场维度上看,尽管大模型带火了向量数据库,多家初创公司受到资本市场青睐,但是其商业化落地和规模化应用的前景仍不明朗:一方面,技术迭代慢,没有新的突破。向量数据库核心技术包括索引、相似度计算、Embedding等,这些技术早已出现,时至今日并没有实现大的创新突破;另…

安全头响应头(三)​X-Content-Type-Options

一 X-Content-Type-Options响应头 说明&#xff1a;先写个框架,后续补充 思考&#xff1a;请求类型是 "style" 和 "script" 是什么意思? script标签 style StyleSheet JavaScript MIME type 文件扩展和Content-Type的映射关系 ① 基础铺垫 ngin…

Kali Linux助您网络安全攻防实战

Kali Linux&#xff1a;黑客与防御者的神器 Kali Linux是一款专为网络安全测试和攻防实践而设计的操作系统。它汇集了大量的安全工具&#xff0c;可以用于渗透测试、漏洞扫描、密码破解等任务&#xff0c;不仅为黑客提供了强大的攻击能力&#xff0c;也为安全防御者提供了测试和…

每日一题 25K个一组翻转链表

题目 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内…

继承和多态C++

这里写目录标题 继承public、protected、private 修饰类的成员public、protected、private 指定继承方式改变访问权限 C继承时的名字遮蔽问题基类成员函数和派生类成员函数不构成重载C基类和派生类的构造函数构造函数的调用顺序基类构造函数调用规则 C基类和派生类的析构函数C多…

我的创作纪念日(256天)

前言 结缘 我与csdn的结缘&#xff0c;之前在创作纪念日&#xff08;128天&#xff09;便已提到&#xff0c;今在此便不再多言 收获 很惭愧&#xff0c;自六月底至八月中旬&#xff0c;因为忙于找工作&#xff0c;奔赴面试求职之际&#xff0c;写博客没有像之前那么勤&#x…

JetPack Compose 学习笔记(持续整理中...)

1.为什么要学&#xff1f; 1.命令式和声明式 UI大战,个人认为命令式UI自定义程度较高,能更深入到性能,内存优化方面,而申明式UI 是现在主流的设计,比如React,React Native,Flutter,Swift UI等等,现在性能也逐渐在变得更好 2.还有一个原因compose 是KMM 是完整跨平台的UI基础 3.…

企业内部知识问答系统面临的挑战及解决方案;小米开启AI大模型内测版本

&#x1f989; AI新闻 &#x1f680; 小米宣布未来五年投入1000亿元&#xff0c;开启AI大模型内测版本 摘要&#xff1a;在小米雷军年度演讲上&#xff0c;小米宣布未来五年将投入1000亿元人民币用于技术研发&#xff0c;同时公布了AI大模型内测版本的邀请测试。该内测版本将…

Java算法_ 二叉树的最大深度(LeetCode_Hot100)

题目描述&#xff1a;给定一个二叉树 &#xff0c;返回其最大深度。root 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 获得更多&#xff1f;算法思路:代码文档&#xff0c;算法解析的私得。 运行效果 完整代码 /*** 2 * Author: LJJ* 3 * Date: 2023/…