Spring源码刨析之配置文件的解析和bean的创建以及生命周期

   public void test1(){
        XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        user u = xmlBeanFactory.getBean("user",org.xhpcd.user.class);
       // System.out.println(u.getStu());
    }

先介绍一个类XmlBeanFactory,这个类负责配置文件的解析和bean的创建和初始化。在Spring中对象信息会被封装为一个BeanDefinition对象,这个对象会保存配置文件中所描述的类的信心比如属性名属性值类名等,以便创建bean时根据BeanDefinition对象的信息反射创建并赋值。

配置文件解析

   xmlbeanfactory内部会创建XmlBeanDefinitionReader用来解析配置文件资源。

把xml文件封装为Document,接着调用注册方法。此方法内部再经过调用会调用到parseBeanDefinitions方法。

 这里的Node就是<bean>标签的信息的封装parseDefaultElement(ele, delegate)方法用来解析常规标签,delegate.parseCustomElement(ele)用来解析自定义标签比如<mvc:annotation-driven></mvc:annotation-driven>这种的或者自定义的标签。

信息封装完毕后,会被存放在XmlBeanFactory的Map文件中,keybeanname,value是beanDefinition。到这里基本xml文件都被解析了。

Bean的创建和赋值

 XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        user u = xmlBeanFactory.getBean("user",org.xhpcd.user.class);

代码在getBean内部有体现

首先transformedBeanName(name)的作用是可能用户提供的是别名转化为beannaem也就是配置文件中bean的id,beanFactory会把创建的bean存放起来以便复用,所以底层使用的就是Map数据结构,根据beanname和bean对象进行存储,主要关注getSingleton(beanName)方法

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

这里就是所谓的三级缓存,它还有一个重要功能解决循环依赖等问题。

由于我们这里主要讲解bean的生命周期和创建,第一次获取肯定是获取不到。上上个图中if分支是判断bean的类型是不是BeanFactory,如果是的话就调用工厂的getObject方法,else分支内就是父子容器的概念,如果在创建XmlBeanFactory时值定了其它的容器那么会把它存放在parentBeanFactory中,那么我们子容器再查找时就会先找自己的内部看是否有,如果没有就找父类的。

接下来注意markBeanAsCreated(beanName)和final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);方法

先看getMergedLocalBeanDefinition(beanName)方法其内部本质是获取对应的bean信息,然后会去查看bean是否有指定继承的类

  <bean id="abs" class="" abstract="true">
        <property name="id" value="1">

        </property>
    </bean>
    <bean id="stu" name="u" class="org.xhpcd.student" parent="abs">

    </bean>

就像这样存在继承的类,spring做的就是把当前类的bean定义信息和父类的bean定义信息组合在一起并返回,然后这里就是完整的bean定义信息

以此递归调用获取父类bean信息,然后会把这些信息存放在mergedBeanDefinitions中。

接下来看之前的markBeanAsCreated(beanName)方法

将指定的 Bean 标记为已创建(或即将创建)。这允许 Bean 工厂优化其缓存,以便重复创建指定的 Bean。现在我们实际上正在创建 bean,让我们重新合并 bean 定义......以防万一它的某些元数据在此期间发生了变化。(注解原话)

接下来 mbd.getDependsOn()方法就是获取bean标签中的depend-on信息解析,不过用的不多。

这段代码是真正创建bean的代码,首先判断bean是单例还是多例又或者是session,request等作用域。先看单例吧,首先getSingleton方法内部传递了一个lambda表达式,作用是为了后续回调此方法,接下来分析getSingleton方法

首先先看 beforeSingletonCreation(beanName) 方法,

protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
       throw new BeanCurrentlyInCreationException(beanName);
    }
}

这段代码就是判断当前类是否被排除并且把它加入到singletonsCurrentlyInCreation集合中,防止在bean的生命周期完成前被多次创建。

然后就是singletonObject = singletonFactory.getObject();此方法就是对传入的表达式的一个方法回调,回调createBean方法,接下来分析此方法

首先解析bean定义信息获取Class信息,

mbdToUse.prepareMethodOverrides()方法是和方法替换有关但平时用的少我会在其他文章进行讲述。

再接下来就是

// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

这段代码涉及Aop,通过@EnableAspect注解注册的bean后处理器,提前返回一个代理对象,代理对象不经过后面其它的后处理器等。以后文章会讲解aop这部分

接下来就是重点 doCreateBean(beanName, mbdToUse, args) 方法

首先创建一个包装对象,里面有一个属性就是我们的bean对象,只是此时还没没进行属性赋值初始化。包装类的作用主要就是用于类型转换,配置文件中把字符串转化为int等。

紧接着创建对应工厂放入三级缓存中,主要用来解决代理循环依赖问题。这里用不到

然后就是popilateBean方法了,这个方法内部进行属性的注入;

先看这个方法此方法内部是获取所有InstantiationAwareBeanPostProcessors

类型的后处理器,然后在最开始进行一些修改。

类型转换

首先尝试获取自定义类型转换器,紧接着对bean定义信息中set方法获取到转换的类型的属性的封装信息PropertyValue进行逐个遍历,内部通过set方法获取类型,然后或取真实的类型转换信息进行转换并赋值给PropertyValue,最终把类型转换后的结果存放在beanwrapper的属性中并进行属性赋值

首先根据  GenericTypeAwarePropertyDescriptor 拿到可写的方法就是set方法,然后利用反射进行属性赋值。

紧接着调用initializeBean方法

执行aware注入方法,紧接着执行Bean后置处理器的before方法然后调用init方法再调用后处理器的after方法,就基本完成创建的生命周期

到这里上面所说的回调方法基本分析完毕。

然后调用 afterSingletonCreation(beanName) 

protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

移除之前上面正在创建bean的信息,然后调用add方法放入一级缓存。到这里bean就创建完毕了

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

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

相关文章

服务器主机关机重启告警

提取时间段内系统操作命名&#xff0c;出现系统重启命令&#xff0c;若要出现及时联系确认 重启命令&#xff1a; reboot / init 6 / shutdown -r now&#xff08;现在重启命令&#xff09; 关机命令&#xff1a; init 0 / shutdown -h now&#xff08;关机&#…

防汛物资仓库管理系统|实现应急物资仓库三维可视化

系统概述 智慧应急物资仓库可视化系统&#xff08;智物资DW-S300&#xff09;采用了 B/S 架构的设计&#xff0c;通过浏览器即可快速登录操作。实现对库房内的应急物资从申购入库、出库、调拨、库内环境监测、维修保养、检测试验、处置报废等全周期、科学、规范的管理。系统以…

恢复MySQL!是我的条件反射,PXB开源的力量...

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

如何进行计量经济分析

计量经济分析是定量分析的常用方法&#xff0c;在经济分析领域有着广泛且重要的应用。计量经济分析以一定的经济理论和统计数据为基础&#xff0c;运用数学、统计学相关方法&#xff0c;通过建立计量模型&#xff0c;并运用软件进行操作&#xff0c;从而实现对经济问题的定量分…

时间序列模型:lag-Llama

项目地址&#xff1a;GitHub - time-series-foundation-models/lag-llama: Lag-Llama: Towards Foundation Models for Probabilistic Time Series Forecasting 论文地址&#xff1a;https://arxiv.org/pdf/2310.08278.pdf hugging-face镜像&#xff1a;https://hf-mirror.c…

QQ农场-phpYeFarm添加数据教程

前置知识 plugin\qqfarm\core\data D:\study-project\testweb\upload\source\plugin\qqfarm\core\data 也就是plugin\qqfarm\core\data是一个缓存文件,如果更新农场数据后,必须要删除才可以 解决种子限制(必须要做才可以添加成功) 你不更改加入了id大于2000直接删除种子 D…

Unity类银河恶魔城学习记录12-14 p136 Merge Skill Tree with Sword skill源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili CharacterStats.cs using System.Collections; using System.Collections.…

如何搭建SearXNG搜索引擎

小白如何搭建SearXNG搜索引擎 前言 国内用户在使用百度、360、搜狗等主流搜索引擎时&#xff0c;面临搜索结果精确度不高、广告泛滥及隐私顾虑等问题。虽然Google以其出色性能备受推崇&#xff0c;但由于无法在国内访问&#xff0c;部分用户转而选择Bing作为折衷方案&#xff…

LeetCode617:合并二叉树

题目描述 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而另一些不会&#xff09;。你需要将这两棵树合并成一棵新二叉树。合并的规则是&#xff1a;如果两个节点重…

OSCP靶场--PayDay

OSCP靶场–PayDay 考点(公共exp文件上传密码复用sudo -l all提权) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap -sV -sC 192.168.153.39 -p- -Pn --min-rate 2500 Starting Nmap 7.92 ( https://nmap.org ) at 2024-04-13 04:52 EDT Nmap scan report for 192…

计算机网络——ARP协议

前言 本博客是博主用于复习计算机网络的博客&#xff0c;如果疏忽出现错误&#xff0c;还望各位指正。 这篇博客是在B站掌芝士zzs这个UP主的视频的总结&#xff0c;讲的非常好。 可以先去看一篇视频&#xff0c;再来参考这篇笔记&#xff08;或者说直接偷走&#xff09;。 …

Spark-机器学习(1)什么是机器学习与MLlib算法库的认识

从这一系列开始&#xff0c;我会带着大家一起了解我们的机器学习&#xff0c;了解我们spark机器学习中的MLIib算法库&#xff0c;知道它大概的模型&#xff0c;熟悉并认识它。同时&#xff0c;本篇文章为个人spark免费专栏的系列文章&#xff0c;有兴趣的可以收藏关注一下&…

双子座 Gemini1.5和谷歌的本质

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

流媒体的安全谁来保障

流媒体的安全谁来保障 说起媒体&#xff0c;我们马上就会想到报纸新闻、广播、电视。 其实所谓的流媒体同我们通常所指的媒体是不一样的&#xff0c; 它只是一个技术名词。流媒体到底是什么&#xff1f;能给我们的生活带来什么&#xff1f;跟小德一起来看看。 流媒体是什么&a…

缓存与数据库的数据一致性解决方案分析

在现代应用中&#xff0c;缓存技术的使用广泛且至关重要&#xff0c;主要是为了提高数据访问速度和优化系统整体性能。缓存通过在内存或更快速的存储系统中存储经常访问的数据副本&#xff0c;使得数据检索变得迅速&#xff0c;从而避免了每次请求都需要从较慢的主存储&#xf…

LeetCode 0705.设计哈希集合:很多人都是这样做的吧【逃】

【LetMeFly】705.设计哈希集合&#xff1a;很多人都是这样做的吧【逃】 力扣题目链接&#xff1a;https://leetcode.cn/problems/design-hashset/ 不使用任何内建的哈希表库设计一个哈希集合&#xff08;HashSet&#xff09;。 实现 MyHashSet 类&#xff1a; void add(key…

04-03 周三 使用印象笔记API批量更新笔记标题

04-03 周三 使用印象笔记API批量更新笔记标题 时间版本修改人描述2024年4月3日11:13:50V0.1宋全恒新建文档 简介 安利印象笔记 在阅读这篇博客之前&#xff0c;首先给大家案例一下印象笔记这个应用&#xff0c;楼主之前使用onenote来记录自己的生活的&#xff0c;也记录了许多…

UI设计规范

一套商城系统的诞生&#xff0c;除了代码的编写&#xff0c;UI设计也至关重要。UI设计关系到商城系统的最终呈现效果&#xff0c;关乎整体商城的风格展现&#xff0c;如果UI设计做不好&#xff0c;带来的负面影响也是不容小觑的。 1、在很多商城系统开发中&#xff0c;有时会有…

基于Java+Vue的校园代购服务管理系统(源码+文档+包运行)

一.系统概述 在新发展的时代&#xff0c;众多的软件被开发出来&#xff0c;给用户带来了很大的选择余地&#xff0c;而且学生越来越追求更个性的需求。在这种时代背景下&#xff0c;学生对校园代购服务订单管理越来越重视&#xff0c;更好的实现校园代购服务的有效发挥&#xf…

YOLTV8 — 大尺度图像目标检测框架(欢迎star)

YOLTV8 — 大尺度图像目标检测框架【ABCnutter/YOLTV8: &#x1f680;】 针对大尺度图像&#xff08;如遥感影像、大尺度工业检测图像等&#xff09;&#xff0c;由于设备的限制&#xff0c;无法利用图像直接进行模型训练。将图像裁剪至小尺度进行训练&#xff0c;再将训练结果…