Sping源码(九)—— Bean的初始化(非懒加载)— getMergedLocalBeanDefinition

序言

前两篇文章介绍了Bean初始化之前的一些准备工作,包括设置BeanFacroty的ConversionService属性以及将Bean进行冻结。这篇文章将会进入到preInstantiateSingletons方法。进一步了解Bean的初始化流程。

preInstantiateSingletons

	public void preInstantiateSingletons() throws BeansException {// 将所有BeanDefinition的名字创建一个集合List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...// 触发所有非延迟加载单例bean的初始化,遍历集合的对象for (String beanName : beanNames) {// 合并父类BeanDefinitionRootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);//省略部分代码....}}

分析

遍历BeanDefinitionName首先做的第一步是合并父类的beanDefinition。
合并过程大致可以分为以下几个步骤:

  1. mergedBeanDefinitions缓存中获取,缓存中有且不需要重新合并定义,则return
  2. 如果 containingBd 为null,则再次从缓存mergedBeanDefinitions中获取。
  3. 如果缓存中依然没有或者需要重新定义。
    3.1 获取parentName,如果parentName = null则创建(克隆)一个RootBeanDefinition封装当前Bean。
    3.2 parentName != null , 且当前beanName = parentName ,使用父工厂获取parentBeanName对应的合并BeanDefinition赋值给父BeanDefinition
    3.3 parentName != null , 且当前beanName != parentName , 如果父类尚未被加载,且父工厂属于ConfigurableBeanFactory
    调用父工厂进行merge操作。

源码

源码中涉及到很多方法的重载和重写,阅读源码时还要仔细分清。
getMergedLocalBeanDefinition
先尝试从缓存中拿。

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {// Quick check on the concurrent map first, with minimal locking.//先尝试从mergedBeanDefinitions缓存中取RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);//如果缓存中有 && 不需要重新合并定义 则直接returnif (mbd != null && !mbd.stale) {return mbd;}//获取 beanName对应的合并BeanDefinition,如果是ChildBeanDefinition 则需要合并return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));}

getMergedBeanDefinition
整体流程步骤上面大致已经介绍。

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)throws BeanDefinitionStoreException {synchronized (this.mergedBeanDefinitions) {RootBeanDefinition mbd = null;RootBeanDefinition previous = null;// Check with full lock now in order to enforce the same merged instance.// 先尝试从mergedBeanDefinitions缓存中取if (containingBd == null) {mbd = this.mergedBeanDefinitions.get(beanName);}if (mbd == null || mbd.stale) {previous = mbd;//parentName为null,说明没有父类BeanDefinition需要合并if (bd.getParentName() == null) {// Use copy of given root bean definition.//如果当前的bd是RootBeanDefinition 则直接克隆if (bd instanceof RootBeanDefinition) {mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();}else {//否则则创建RootBeanDefinitionmbd = new RootBeanDefinition(bd);}}else {// Child bean definition: needs to be merged with parent.//parentName不为null,则需要合并BeanDefinition pbd;try {//通过transformedBeanName方法获取parentBean的最终别名String parentBeanName = transformedBeanName(bd.getParentName());//如果当前beanName不等于parentBeanNameif (!beanName.equals(parentBeanName)) {// 获取parentBeanName的"合并的"BeanDefinition赋值给pdbpbd = getMergedBeanDefinition(parentBeanName);}else {//如果当前beanName等于parentBeanName,则获取父类工厂BeanFactory parent = getParentBeanFactory();//如果父类工厂是ConfigurableBeanFactory,则使用父工厂获取parentBeanName对应的合并BeanDefinition赋值给pdbif (parent instanceof ConfigurableBeanFactory) {pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);}}}// Deep copy with overridden values.//生成RootBeanDefinitionmbd = new RootBeanDefinition(pbd);mbd.overrideFrom(bd);}// Set default singleton scope, if not configured before.//设置默认的scopeif (!StringUtils.hasLength(mbd.getScope())) {mbd.setScope(SCOPE_SINGLETON);}if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {mbd.setScope(containingBd.getScope());}//暂时缓存合并的bean定义(稍后可能仍会重新合并以获取元数据更正),如果没有传入包含bean定义 且 当前工厂是同意缓存bean元数据//cacheBeanMetadata:默认为true 代表是缓存bean元数据,还是在每次访问时重新获取它if (containingBd == null && isCacheBeanMetadata()) {this.mergedBeanDefinitions.put(beanName, mbd);}}if (previous != null) {copyRelevantMergedBeanDefinitionCaches(previous, mbd);}return mbd;}}

getMergedBeanDefinition
父类调用的((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);

public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {//获取实际的beanNameString beanName = transformedBeanName(name);// Efficiently check whether bean definition exists in this factory.// 当前beanName在当前工厂的beanDefinitionMap中不存在 && 父工厂 属于 ConfigurableBeanFactoryif (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {//使用父工厂返回beanName的合并BeanDefinition【如有必要,将子bean定义与其父级合并】return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);}// Resolve merged bean definition locally.//本地解决合并的bean定义return getMergedLocalBeanDefinition(beanName);}

流程图

在这里插入图片描述

总结

总结:
没有父类就创建一个RootBeanDefinition封装信息、放入缓存后返回。
有父类则调用父类工厂进行merge操作后,同样创建RootBeanDefinition封装父类信息后返回给子类,子类拿到父类返回的BeanDefinition后再次封装进RootBeanDefinition,设置信息后、放入缓存返回。

值得一提的是mergedBeanDefinitions变量,在Spring中有很多类似的应用,将不太变化且经常可以用到的东西放入缓存中,用时先在缓存中获取,包括beanDefinitionMap等变量都是如此。

mergedBeanDefinitions变量其实我们并不是第一次见到,源码中在执行invokeBeanFactoryPostProcessors方法时,会调用beanFactory.getBeanNamesForType方法获取系统中实现了BeanFactoryPostProcessorBeanDefinitionRegistoryPostProcessor的类。

beanFactory.getBeanNamesForType方法中就有beaDefinition的merge操作,感兴趣可以再了解了解。

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

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

相关文章

这个开源的多模态模型无敌。。。

InternVL 由 OpenGVLab 开发&#xff0c;是一个开源的多模态对话模型&#xff0c;其性能接近商业化的 GPT-4V 模型。 GPT-4V 是 OpenAI 去年推出的多模态模型&#xff0c;使用它你可以分析所需的任何类型的图像并获取有关该图像的信息。 1. InternVL 开源模型 而今天的主角研究…

香港苏州商会、香港青年科学家协会博士团参观李良济,加强人才交流,促进科创合作与共赢

近日&#xff0c;香港苏州商会、香港青年科学家协会联合主办的苏港青年科创交流会成功举行&#xff0c;香港青年科学家协会博士团神州行苏州站启动。 5月26日&#xff0c;香港苏州商会及香港青年科学家协会博士团走进李良济&#xff0c;先后参观了李良济中医药文化展厅&#xf…

游戏联运平台如何助力游戏行业飞速发展?

随着科技的进步和互联网的普及&#xff0c;游戏行业正以前所未有的速度飞速发展。在这个过程中&#xff0c;游戏联运平台凭借其独特的优势和功能&#xff0c;成为了推动游戏行业腾飞的关键力量。本文将探讨游戏联运平台如何助力游戏行业实现飞速发展。 一、游戏联运平台的定义与…

Linux下多线程的相关概念

&#x1f916;个人主页&#xff1a;晚风相伴-CSDN博客 &#x1f496;如果觉得内容对你有帮助的话&#xff0c;还请给博主一键三连&#xff08;点赞&#x1f49c;、收藏&#x1f9e1;、关注&#x1f49a;&#xff09;吧 &#x1f64f;如果内容有误或者有写的不好的地方的话&…

62、 忠北国立大学计算机科学系:FingerNet-专门用于细致MI分类的神经网络模型

本文由泡菜国高校于2024年3月6日发表于arXiv&#xff0c;做了一个专门处理运动想象信号的CNN模型&#xff0c;融合了EEGNet和DeepConvNet。 FingerNet是一种专门用于细致MI分类的网络&#xff0c;利用了时间特征&#xff0c;在相同手部分类任务中表现出比EEGNet和DeepConvNet更…

使用 MySQL 触发器 + 统计学生表实时计算表数据量

要使用 MySQL 触发器实时计算表数据量&#xff0c;您可以创建一个触发器&#xff0c;当插入、更新或删除学生表的数据时&#xff0c;触发器就会更新另一个表中保存的学生表数据量信息。以下是一个示例&#xff1a; 首先&#xff0c;假设您有一个名为 students 的学生表&#x…

低代码开发难吗?

在软件开发的多样化浪潮中&#xff0c;低代码开发平台以其简化的编程模型&#xff0c;为IT行业带来了新的活力。作为一位资深的IT技术员&#xff0c;我对低代码开发平台的易用性和强大功能有着深刻的认识。今天&#xff0c;我将分享我对YDUIbuilder这一免费开源低代码平台的使用…

0.25W 1.5KVDC~3KVDC 隔离超小型单输出 DC/DC 电源模块——TKE-W25系列

TKE-W25系列隔离超小型单输出 DC/DC 电源模块是一款超小型单输出电源模块&#xff0c;工业级环境温度&#xff0c;用于PCB安装的国际标准结构。此系列产品小巧&#xff0c;效率高&#xff0c;低输出纹波,用于需要电压转换和隔离的场合&#xff0c;封装有SIP和DIP可选。

出租房水电抄表系统的全面解析

1.系统定义和功能 出租房水电抄表系统是一种智能的可视化工具&#xff0c;关键用于解决房东在经营好几个出租房源时&#xff0c;对水电的使用量统计分析、收费和管理上的问题。通过自动化抄表、收费和通告&#xff0c;此系统减轻了房东的工作负担&#xff0c;提高了效率&#…

达梦数据库安装手册

首先了解达梦数据库相关内容&#xff1a; 达梦在线服务平台 下载windows版本开发版&#xff0c;将下载的文件解压。进行安装 2、安装流程&#xff0c;默认选择下一步。 3、安装引导&#xff0c;默认下一步&#xff0c;安装实例可以进行修改 4、最后一步记录一下创建的摘要 …

JavaDS-学习数据结构之如果从零开始手搓顺序表,顺带学习自定义异常怎么用!

前言 笔者开始学习数据结构了,虽然笔者已经会用了,不管是C 中的stl亦或是Java 中的集合,为了算法比赛多少都突击过,但只知其然而不知其所以然,还是会限制发展的,因此,笔者写下这篇博客.内容是手搓一个顺序表.顺带加一点异常的使用,大伙看个乐子就好了.有错误直接私信喷我就好了…

清华大学提出IFT对齐算法,打破SFT与RLHF局限性

监督微调&#xff08;Supervised Fine-Tuning, SFT&#xff09;和基于人类反馈的强化学习&#xff08;Reinforcement Learning from Human Feedback, RLHF&#xff09;是预训练后提升语言模型能力的两大基础流程&#xff0c;其目标是使模型更贴近人类的偏好和需求。 考虑到监督…

Java基础入门day60

day60 购物车案例补充 设置欢迎页 打开也系统&#xff0c;就可以直接看到商品列表页面 之前曾经设置过欢迎页&#xff0c;都是针对页面&#xff0c;可以有html页面&#xff0c;也可以有jsp页面 但是今天我们将一个servlet设置成欢迎页 在web.xml文件中设置欢迎页 <welcome…

【C++】牛客——JZ38 字符串的排列

✨题目链接&#xff1a; JZ38 字符串的排列 ✨题目描述 输入一个长度为 n 字符串&#xff0c;打印出该字符串中字符的所有排列&#xff0c;你可以以任意顺序返回这个字符串数组。 例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。 数…

Pi 母公司将开发情感 AI 商业机器人;Meta 科学家:Sora 不是视频生成唯一方向丨RTE 开发者日报 Vol.214

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「…

揭秘IDM:数字资产管理的未来之星

在当今数字化时代&#xff0c;数字资产管理的重要性日益凸显。随着科技的飞速发展&#xff0c;越来越多的企业和个人开始关注如何有效管理和保护他们的数字资产。在这个过程中&#xff0c;IDM&#xff08;身份管理系统&#xff09;逐渐成为了热门话题。IDM作为一种新兴的技术手…

动手学操作系统(四、MBR读取硬盘加载Loader)

动手学操作系统&#xff08;四、MBR读取硬盘加载Loader&#xff09; 在上一节中&#xff0c;我们学习了使用MBR来直接控制显卡进行显示&#xff0c;在这一节中我们学习如何让MBR来操作硬盘&#xff0c;加载Loader来完成操作系统的后续启动过程。 文章目录 动手学操作系统&…

神经网络与深度学习——第14章 深度强化学习

本文讨论的内容参考自《神经网络与深度学习》https://nndl.github.io/ 第14章 深度强化学习 深度强化学习 强化学习&#xff08;Reinforcement Learning&#xff0c;RL&#xff09;&#xff0c;也叫增强学习&#xff0c;是指一类从与环境交互中不断学习的问题以及解决这类问题…

SQL刷题笔记day4补

1题目 我的正确代码 select e.last_name,e.first_name,d.dept_name from employees e left join (select departments.dept_name,dept_emp.emp_no,dept_emp.dept_no from departments join dept_emp on departments.dept_nodept_emp.dept_no) d on e.emp_nod.emp_no复盘&…

(文章复现)分布式电源接入配电网承载力评估方法研究

参考文献&#xff1a; [1]郝文斌,孟志高,张勇,等.新型电力系统下多分布式电源接入配电网承载力评估方法研究[J].电力系统保护与控制,2023,51(14):23-33. 1.摘要 随着光伏和风电等多种分布式电源的接入&#xff0c;使得传统配电网的结构及其运行状态发生了较大改变。因此&…