孙哥Spring源码第二集

第二集 XmlBeanDefinitionReader解析xml为Document、Document经过默认标签的解析成Bean

【视频来源于:B站up主孙帅suns Spring源码视频】【微信号:suns45】

2.1、工厂的分类介绍

上节课确定了主题,Spring工厂 容器 在讲这个主题的过程当中,我们需要大家注意的是什么呢?先了解到的是什么?工厂的分类

Spring很多细致的工厂,作为根工厂就是BeanFactory这是整个Spring当中最为底层 最为核心的一个接口,它提供了进行访问和操作的最基本的功能,进而他又衍生出来了很多很多子接口,spring设计的语言是什么呢?我每衍生出来一个子接口,我就是在原有的这个工厂上做了扩展,这是它一个比较有意思的设计,它通过父工厂去扩展子工程的方式让spring的工厂富有很多很多的能力。

当然这些工厂里面需要大家关注的是

2.1.1 ConfigurableBeanFactory作用

ConfigurableBeanFactory可配置的工厂,实际上所配置的工厂它的特点是 配置相关对象的单实例 和多实例 类型转换器 和后置处理bean 相关的内容。

2.1.2 AutowireCapableBeanFactory作用

AutowireCapableBeanFactory这个工厂的特点是 加上了自动注入和生命周期相关的功能。

2.1.3 ListableBeanFactory作用

ListableBeanFactory :最重要的工厂也是Spring提供的最强大的工厂,实现了 Spring定义的绝大多数的工厂接口 都是被这个接口所实现的,应用它的时候 会使用它的实现类,叫做DefaultListableBeanFactory到这个层面上来讲实际上我们spring工厂的应用 就已经到了非常非常底层的层面,这个底层的层面就是这个工厂就是整个Spring工厂的代言人,拥有spring工厂的绝大多数功能,但是我们说 因为我们在开发过程当中需要使用xml做配置,来设置我们需要的工厂来创建对象,所以我们在开发的过程当中可能会使用它的一个子类,
叫做XmlBeanFactory,上次我们关注过这个事儿,发现这个类已经过期了,那这个类过期了没有关系,后续我们还会通过别的方式来替代,但其实上XmlBeanFactory在开发当中是非常重要的东西,先研究这个。

2.1.4 作为XmlBeanFactory它最大的特点是什么呢?

可以帮助我们读取器xml文件进而创建相应的对象,

2.1.5 那作为应用层面上来就讲,我们怎么使用XmlBeanFactory呢?

XmlBeanFactory的使用实际上是通过这样的方式来完成的,
BeanFactory beanFactory = new XmlBeanFactory(Resouce读取xml信息)【第一行】
进而我们可以获取对应的对象了 beanFactory.getBean(“”) 来获取 最终的对象,那么在这儿需要大家注意的是什么呢?
看似非常简单的两行代码实际上蕴含了非常多的内容,而这每一个蕴含的内存都是我们后续需要在源码分析的层面上一个一个去解决它。
比如说它蕴含了什么样的东西呢?
作为这个代码来讲,先看第一行,看起来我们就是读取了配置文件,创建了工厂,但是在这个过程中,它包含什么样的内存呢?
1、怎么读取配置文件 怎么获得的IO资源
2、读取了配置文件后,如何在Spring中以对象的形式来进行封装
3、根据配置信息来创建对象
4、所创建对象的生命周期
实际上这四个内容已经完整性的涵盖了IOC工厂部分核心内容
比如说 你在参加这个课程之前 也参加过别的学习,你会问它是怎么完成注入的,但实际上注入的这个环境它是在哪完成的?其实是在生命周期当中体现的,有些同学说的这个循环引用这个问题 三级缓存二级缓存一级缓存这些东西,它是在哪体现的呢?它是在创建对象以及创建对象的生命周期当中,所以大家的很多东西都把它具化到了某一个点,那实际上这些点 都会在这个主题当中来体现出来。
那这个就是一个完整的层级关系,那只有把这些层级大家掌握好之后,在根据每个层级进行发散,进行展开,把涉及到的方方面面讲完。这个时候大家就可以做到作为整个spring来说是一个大成。

跟同学聊天的时候说过,我们在研究任何一个框架的过程中,研究源码 是没有任何一个人 可以做到的是 把它的源码的某个方法,每一个方法 研究的特别透彻,那是不可能的,为什么呢?因为它里面有很多校验,有很多特性,我们在开发的过程当中 基本不用,你都不用你怎么又能看的懂呢? 今天我们就可以看到 像集成 像look-method 或者 replace-method 我相信这些东西 大家平时开发的时候 几乎没用过。除了跟着官方的文档写过demo,我也没用过,所以那些东西注定它就是其中的一个环节,我们抓大放小,我们抓住我们在开发中常用的,把它的组织结构说明白,这才是我们在学习过程中很重要的内容,这是大家需要注意的。

2.2、Spring对IO资源的处理

上次课,我们讲了Spring是怎么来读取配置文件获得IO资源的?
作为spring来讲,在打开IO读文件的过程当中有自己的封装,那它自己的这个封装,是通过什么对象来完成的呢?它其实是通过一个Resource接口来完成的相关配置信息的读取,当然它定义成接口会有很多实现,这根据你的资源不同 以及 读取方式不同 你去选择去使用某一个具体的实现类,比如说 ClassPathResouce ,ServletContextResource,这些对应的实现类,每一个实现类实际它最终的目的都是为了读取对应的资源,可是它读取的方式都有不同的行为,所以人家设计好了这个接口,所以最终读的过程中,我们只要获取一个核心类就可以了,这个核心类是什么呢?InputStream因为甭管是什么资源,它在本地还是在网络,不用管它是什么形式 是一个类是一个文件是一个jar包这都不重要,因为最后 我们java虚拟机在获取相应内容的时候,我们只要拿到它的输入流,根据输入流的接口来进行读取即可。 这是第一个内容,这个内容相对来讲是比较好理解的。

2.2.1 BeanDefinition的由来

我们当获取了这些信息输入流之后,显然我们要读这些内容了,
比如说我此时有一个applicationConext.xml
这里面有bean id=user class=”xxx.xxx.User“ bean id=account class=”xxx.xxx.Account “ ,有了这个配置文件之后,按照spring的语义来讲,需要通过我们的Resource接口它对应的一个实现类来进行读取获得 InputStream 输入流,其实你会发现 这个Resource所做的事情,很类似于Mybatis当中的 第一步开发,它最终的目的就是打开输入流读到虚拟机当中来就行了。
文件当中所对应的ID信息,类的信息乃至其他相关的信息,它是不是要在虚拟机当中进行存储呢?因为我读进来的目的是为了用,而我在用之前 显示是要把你存起来的,那以什么样的形式来存呢,那显然应该以对象的形式来存,所以这些配置文件的相关信息,那它最终在虚拟机当中以对象的形式来体现的 实际上这个东西,我们只要学框架,都是这个效果。那以对象的形式来存,在spring当中,它把这些配置信息以什么样的对象来进行存储的呢?我们说是BeanDefinition的形式进行存储,我们可以看下对应BeanDefinition的源码,你会发现BeanDefintion最终的目的就是为了存储对于xml的信息,那当然你会发现这个BeanDefinition它是一个接口,那我们在应用的过程当中,显然不可能使用这个接口,那我们一定会使用它的实现类,它的实现类有哪些呢?你会发现它的实现类有很多,其中一个叫做AbstractBeanDefinition,又一个叫GenericBeanDefinition它的应用是最为广泛的,这个是需要大家注意的,这是核心当中我们所使用的一个类, 最终Spring把读取的配置信息封装成了GenericBeanDefinition。

2.2.1.1 GenericBeanDefinition的介绍

看一下继承关系。
image-20230506105540370

BeanDefinition是核心封装的配置信息的内容
最常用的是GenericBeanDefinition只有它才能被实例化
所以最终这个BeanDefinition会以GenericBeanDefinition有所体现。
这就是我们说的最终Spring在读取完配置文件之后它要做的事情,要把配置文件的相关信息封装成BeanDefinition

2.2.2 XmlBeanDefinitionReader 的介绍

那下面一个问题是什么呢?作为我们来讲我们写了一个xml,那spring通过Resource进行了读取获得了输入流,那输入流到BeanDefinition这个封装的这个过程,它是由谁来完成的呢?你拿到的是输入流,但最终拿到的是成品 是封装好的对象BeanDefinition,而在这个过程当中谁负责把输入流相关的内容封装成BeanDefinition? 那实际上这里面又涉及到了Spring另外的一个核心类型 叫做

XmlBeanDefinitionReader 主要作用是获取输入流之后把对应的配置文件信息封装成BeanDefinition,这是它的一个核心作用 。

那实际上因为在处理过程中需要XmlBeanDefinitionReader来做这样的转换【输入流->BeanDefinition】而这个类型又是在哪来应用的呢?实际上这个类型又是在我们说的XmlBeanFactory当中使用的,所以这就解释了我们在应用过程当中,需要使用XMLBeanFactory,因为XmlBeanFactory具备所有工厂的能力,同时它里面还有XmlBeanDefinitionReader,有了这两个东西之后,它才能最终把xml的信息封装成BeanDefintion,所以这就是为什么我们在应用的过程当中,要使用XmlBeanFactory的原因,如果它过期了,你就只能单独调用XmlBeanDefinitionReader

看对应的源码搜索什么呢?XmlBeanDefinitionReader
这个类型核心的作用是什么呢?Bean定义阅读器,用于XML Bean定义,那么作为这个类来讲,它是在哪应用的呢?
在XmlBeanFactory中来使用的,首先就new XmlBeanDefinitionReader,这个时候你就会发现它有读取的能力,我们在后续的开发过程中就会使用它。

2.2.2.1 DefaultListableBeanFactroy替换XmlBeanFactory

如果后续真想把XmlBeanFactory干掉,用我们这个default来处理,那么咱们应该怎么办呢?
使用DefaultListableBeanFactroy替换XmlBeanFactory 实际上替换的思路很简单,使用DefaultListableBeanFactory+XmlBeanDefinitionReader来进行替换
image-20230506135502517
通过演示,告诉大家的一个问题是,如果我们用XmlBeanFactory来做的话,它是简单的它内部已经封装了XmlBeanDefinitionReader,
但是XmlBeanFactory已经过期,可能有些同学会产生一个问题时,看过期的代码不舒服,想替换该怎么替换呢?
XmlBeanFactory最大的特点是 里面 有XmlBeanDefintionReader 把对应xml 封装成BeanDefinition,那我们既然找到了这个XmlBeanDefintionReader 类是XmlBeanFactory具有的核心,分析完这个事儿之后,
那下面,用原始的它的父类DefaultListableBeanFactory来做这个事,我们只需要嫁接 XmlBeanDefinitionReader就可以了。
最后你会发现这4行代码干的事和1行代码干的事儿是完全一样的
image-20230506140853306

后续为了演示 使用XmlBeanFactroy,如果想使用DefaultListableBeanFactory 替换一下就可以了,本质上来讲是没有任何区别的。
后续为了代码运行快一点,就直接使用Maven项目了,不在spring源码上运行了,你要是感觉有重要的地方,你可以后续自行把注释补全到源码上。

2.3 从输入流转化成BeanDefinition的过程

说起来其实是容易的,这个容易是什么呢? 就是我们通过Resource获取输入流来读取XML的东西,进而XmlBeanDefinitionReader把xml转化成BeanDefintion,这个过程说起来很简单,大家基本上可能做到了一个基本的了解,可是具体的过程,它是怎么来完成的呢,输入流到BeanDefinition它的源码又是怎么来完成的呢?这就是我们下面要给大家讲解的核心了

2.3.1 Spring多工厂问题

读取完配置文件之后,如何在Spring中以BeanDefinition的形式在Spring当中进行存储,那就涉及到下面的内容了。
Spring底层如何做到通过XmlBeanDefinitionReader 读取 XML 封装成我们的BeanDefinition。
作为Spring来讲 是允许 在一个工程中 有多个Spring工厂同时出现的,当然这种情况是非常少见的,

image-20230506151911103 如果和开发相互印证的话, 只有在SpirngMVC中 父子容器 DispathcherServlet 叫做 childFactroy,还有一个是 ContextLoaderListener叫做rootFactory,这就是父子容器了,所以说在整个的设计过程当中,它经常会兼顾有可能会出现父容器的情况,但是这在开发过程当中是非常少见的,所以你在阅读源码的过程中发现有父容器的问题,可以选择性的把它忽略掉,因为这种情况或者场景是非常少见的。

2.3.2 XmlBeanDefintionReader#loadBeanDefinitions的讲解

印证配置文件最终是通过XmlBeanDefintionReader来完成的
image-20230506152102396

————————

考虑到Resource是需要编码的所以就又包了一层 EncodedResource,需要大家注意的是在现在默认的开发过程当中这个编不编码其实是没用的, Encoded的这个编码默认是被设置成空的了,所以这块没有任何的操作就到了下一步,你可以把EncoderResouce当成Resource来看。

image-20230506152557429 ————————

往下继续走 ,这次是实质上进行读取的地方

2.3.2.1 读取多个配置文件

考虑到有多个配置文件的设置,大家不需要关注,这块儿是没有意义的

image-20230506152843580

————————

2.3.2.2 获取输入流

最核心的是这块,encodedResouce.getResource().getInputStream()是什么意思呢?

image-20230506153138748 encodedResouce就是我们刚才封装的Resource,就是Spring定义的Resource接口, 而这个Resource这个接口上次讲了,它实现了InputStream,这块获取的就是 配置文件的输入流。 InputStream inputStream = new InputSource(inputStream)它是什么意思呢? 这个InputStream是专门进行XML解析的工具类,所从属的包是org.xml.sax,实际上它就是sax解析,这个工具不是spring的,是java提供的,这就是大家为什么为乱的原因。 这块的核心代码 核心主旨就是把输入流获得之后进行xml解析 封装好解析的工具类,这个工具类还不是spring提供的,是java提供的。 当然如果这块你有编码的话,还可以设置编码,一般情况下encodedResource编码默认是null,下面的if是不会执行的。

这是最后解析的核心,这个解析里面你会发现什么呢?第一给了配置文件encoded.getResource(),第二给了配置文件做xml解析的工具inputSource,这块最终的目的是不是就可以帮我们生成BeanDefinition。

2.3.2.3 doLoadBeanDefintions的讲解

这块doLoadBeanDefintions才是核心

image-20230506211721244

作用:实际上是从指定的XML文件加载bean定义。

2.2.2.4 关于document的理解
image-20230506212054681

doLoadDocument给了inputSource和resource最后成了一个Document,而这个Document是干嘛的呢?
各位一定要注意Document,Document还是xml解析所封装的一个类型,Document和Spring没有关系,它是xml解析所封装的一个对象
换句话来说你用InputSource去读xml会先把xml封装成Document这是XML解析相关的操作,这是需要大家注意的,但是我们在开发过程当中一般不会直接使用Document,这个Documenet和Spring是没有关系的,是别人封装的,Spring是不愿意用的,用起来也不方便,所以Spring后续还要做一件事是什么呢?就是要把Document再转换成Spring需要的BeanDefinition。
其实这两行代码干的就是这两件事情。
第一件事情是什么?我先解析xml获得xml封装的Document,之后再把Document转换成BeanDefinition,下面一个方法就把doc放入registerBeanDefinitions(doc,resource)。

其实这个过程就很类似于什么呢?很类似于这样的一件事儿,就是我们在java开发的过程当中,如果我们访问数据库你会知道,使用JDBC访问数据库,如果JDBC去查询的话,得到的结果是什么?是ResultSet,但是我们在开发的过程中会使用ResultSet吗?我们显然是不会使用这个ResultSet的,会了后续我们开发起来方便,我们会把ResultSet里面的数据转化成我们需要的实体,这样对于我们程序猿编程来讲更加方便,所以你会发现这个数据库里面的数据是转了两次,一次是先转成ResultSet,一次又转换成了实体,后续我们程序猿再用。
那Spring设计也是一样的,首先把xml解析变成了document,xml的内容都封装在了document里面,document是有自己的结构的。
但是Spring用起来不方便,就好像我们用Result不方便一样,Spring就把用起来不方便的Document转化成了BeanDefinition。
而我们把使用起来不方便的ResultSet转化成了实体。这样一类比你就明白了它为啥要转换两次了吧? 为了后续操作方便。
所以我们说整个Document存的就是所有配置文件的信息,只不过它存起来比较费劲,存了一些比较复杂的机构,作为Spring它用起来不方便,所以它就不用这块的内容了,这就是我们所说的doLoadDocument的作用。

下面的一部就是拿到Document之后 再变成BeanDefinition,其实这块就是registerBeanDefinitions,这个方法为啥会返回一个count值,其实目的很简单就是知道封装了几个BeanDefinition,返回的是封装个数,按照我们的配置文件如果现在来写一个bean,就会返回

2.2.2.5 registerBeanDefinitions的讲解

接下来看registerBeanDefinitions

image-20230506215820816

这个方法来看的话,作用就是通过我们给的文档在容器中注册bean。它整个的代码逻辑是什么呢?
getRegistry().getBeanDefinitionCount() 记录一下现在的这个注册器注册了多少个BeanDefinition。
后续再拿getRegistry().getBeanDefinitionCount()最新的数量减去之前记录的就是增量了,
这块的核心其实是documentReader.registerBeanDefinitions,
进入这个registerBeanDefinitions方法,

image-20230506220837195

需要的一个小技巧是什么呢?do开头的往往是实质上做的事情。

2.2.2.5.1 profile的处理
image-20230506220825827

这个代码实际上都蕴含了什么样的内容呢?

root代表的是我们配置文件的根标记,在整个spring的配置文件当中,我们大家可以清晰的看到它的根标记是什么?

image-20230506221116468

beans

image-20230506221349313 是什么意思呢?
去获取这个常量定义的,那这个常量是什么东西呢?发现这个常量是Profile
image-20230506221246710

这块想要达到的效果是什么呢?就是处理我们的Profile标签。
你们见过在Spring配置文件当中,去使用Profile,大家见过吗

image-20230506221558657

其实我们刚才说的这一if语句,去解析beans下面的profile标签。
image-20230506221623496

这个用过吗?这可能就是Spring不太友好的地方,你可能遇到了你永远都不会用到的标签,甚至你没听说过的标签,上来就一堆代码,最后在这儿就懵逼了。
说一下Profile,Profile是什么意思呢?Spring在这里设计的时候它 是可以区分环境的 ,什么叫区分环境呢?
比如我此时定义一个dev
我这儿定义一个production
在dev里面配置的这些bean标签,就是开发环境使用的这些对象和相应的配置。
比如说我们又定义了production,在production配置了相关的bean标签和相关的配置,它就是在生成环境下所使用的配置,那你是不是通过Profile的切换就可以完成不同环境的改变,而不需要涉及代码的修改,能听得懂吗?
这个在SpringBoot里面也有类似的东西包括在Maven里面也有Profile,Profile代表的就是开发环境,我们可以指定不同的环境在配置相应的内容,如果这样后续 我们想使用生产环境,就可以使用production,要是使用别的环境可以使用dev这套
image-20230506223656450
那下面的一个问题就又来了,你现在设置了Profile之后,你是不是为了进行相应环境的区分啊?
比如说我们后续会使用dev/production,那么我们后续在哪区分呢?
这个区分一般在SpringMVC上用的比较多一点,在SpringMVC中我们有一个Context-Param的配置,

<context-param>
    <param-name>Spring.profile.active</param-name>
    <param-value>springmvc配置文件的位置</param-value>
    <!--让dev起作用
	<param-value>dev</param-value> 对应的就是beans中profile名字的dev
	-->
</context-param>

如果对这块儿不理解,在学SpringBoot的时候 永远把这些东西当成新的东西,实际上不是新的,其实在SpringMVC里面是有的,SpringBoot就是在Spring和SpringMVC包了一层,没有创造。

这块的话搞的是Profile的读取,和实际开发的关联度不大的,实际上我们很少这么写。

2.2.2.5.2 parseBeanDefinitions(root,this.delegate)的讲解

所以下面的重要点是

image-20230506225123282 parseBeanDefinitions(root【根标签】,this.delegate【相应的注册器】) 现在扒了这么多层,才扒到了解析的核心,叫做parseBeanDefinition。 进去这个方法查看 image-20230506225226358

解析一个一个的子节点,在for循环里面遍历,发现最终的遍历是通过这两个方法来体现的

image-20230506225504799 它的作用是什么呢? 它是解析基本标签的, 基本标签都有什么呢? bean id class scope parent init-method 这些属性都是基本标签包括 property name value还有构造函数标签 constructor-arg image-20230506225527338 这个解析的是自定义标签,这是这两个方法的区别,那下面的这个问题就很自然的要分析了,要分析分析什么呢? 什么是基本标签,什么是自定义标签呢? 后续在开发当中,用了新的命名空间的标签。 比如说 context:propertyplace-holder context:component-scan tx:annotation-driven mvc:annotation-drivent aop:config 这些有命名空间头的标签,都叫做自定义标签。 自定义标签实际上是大家最有争议的地方,因为自定义标签吧,我们用它特别简单,它直接减少了代码量,这是从spring2.0之后引入的命名空间,spring1.x没有,spring1.x配置量特别多,但是它也有好处。 使用基本标签配置的好处就是结构特别清晰,我使用了那些类,调用了那些方法完成了什么样的注入,我都是一目了然, 但是我用了这些自定义标签之后,它是简单了,你比如说我一个mvc:annotation-driver它里面封装了好几个类的创建,但是我只使用了这个标签,那些类我就找不到看不见,对于我们分析它的运行过程来讲是非常麻烦的,而这就直接影响到了什么呢?影响了我们后续对SpringBoot的学习,因为SpringBoot里面会大量的使用配置的注解替换schema 所对应的类,而如果这些类你都不知道,在用注解的时候,你就特别懵逼了,比如说我们经常使用XXXMVC的注解,封装的就是mvc:annotation-driver这个标签,那它对应的那些类呢?它又注册了那些东西呢?它能解决什么样的问题呢?你就会很懵逼了。 所以我们这块的学习,一方面把标签怎么解析讲出来,更重要的是自定义标签的这些标签头 到底对应那些类,我们日后能不能自己定义,这才是核心。

首先我们先看解析基本标签的方式,最传统的beans bean这套东西,当然这里面会涉及到很多属性,你可能不一定听说过,这都是很正常的。

2.2.3 parseBeanDefinitions中ParseDefaultElemenet 默认标签的处理

我们直接到 image-20230506232231380 往下看
image-20230507085638958

2.2.3.1 处理import标签
image-20230507100435123

第一个if解决的是import标签

import标签的作用是什么呢?
引入配置文件
image-20230507085926464
这个import很少用,配置文件一般都通过通配的方式来处理,不常见。

2.2.3.2 处理alias标签
image-20230507100501364

第二个if解决的是alias标签

alias标签是什么意思?别名
image-20230507090145538
等价于
image-20230507090236619

2.2.3.3 处理bean标签
image-20230507100521274

第三个if解决的是bean标签
我最应该研究的就是这个方法,它处理的是bean标签的解析
image-20230507090550291

delegate是一个委托对象,实际上就是BeanDefinitionParser。ele就是xml的内容。

2.2.3.3.1 parseBeanDefinitionElement处理
image-20230507090728347

把给我们的元素解析成BeanDefinitionHolder
这个BeanDefinitionHolder是什么呢?这个就是对BeanDefinition做了一层包装。

image-20230507090859744 存了BeanDefinition,beanName和多个别名aliase。 BeanDefinitionHolder这个类实际上包了一层BeanDefinition,同时又把它的名字和它的别名都拿出来了,为什么? 用着方便,提取到外层,调用起来方便。 这行代码的作用:就是把xml标签信息封装到BeanDefinitionHolder中。 标签信息:bean property construtor 进入方法内部看 image-20230507101057993 image-20230507100850203
代码核心:获取id属性和name属性,准备一个alias集合
image-20230507100905001
代码核心:解析别名,封装到List集合中
image-20230507100916520
代码核心:把name的一个值给取出来作为id使用
image-20230507100951259
代码核心:确定注册表中【注册到BeanDefinition的Map里面】的id没有冲突。
image-20230507101015567
代码核心:处理除了name 和id之外的其他标签信息封装成AbstractBeanDefinition,进入这个方法
image-20230507101131943

解析了class 标签 parent标签,还有Lookup 、 ReplacedMethod、ConstructorArg、Property等等
Lookup 方法查找和ReplacedMethod 方法替换 没用过是正常的,但是官方文档是详细介绍过的,lookup-method除了在面试的时候遇到过以外,其他没见过,意义不大。
解析到这里你会发现 init-method depends-on factory-method factory-bean都还没解析呢,这些标签在什么地方解析的呢?是在
image-20230507094343857
进入这个方法查看
image-20230507094507891

查看parsePropertyElements
image-20230507094640734
image-20230507094657514

你会发现bd.getPropertyValues().addPropertyValue最终property都被封装成了BeanDefinition的PropertyValues

代码核心:bean标签的id和name都没有,spring会按照默认的算法给我们生成一个。
image-20230507101243776

总结:封装成BeanDefinitionHolder最终都在这个里面做各种id的解析,各种标签的解析 ,各种名字的解析包括别名的解析,包括bean没有名字的创建,就是这个方法做的事情。

2.2.3.3.2 decorateBeanDefinitionIfRequired处理
image-20230507091201653 如果bdHolder不为空,为什么还要做delegate.decorateBeanDefinitionIfRequired(ele,bdHolder)这件事呢? 为了处理bean标签里面嵌套的自定义标签。 image-20230507091524949

注册BeanDefinition,这是什么意思呢?我们不是把spring的配置信息,每个bean标签最终是不是都会被封装成BeanDefinition呢?
是不是会有很多BeanDefinition,有很多BeanDefinition,我们创建BeanDefinition是为了后续我们创建对象使用这些数据呢?那我要想创建对象使用这些数据,那这n个BeanDefinition,最终要给存起来啊,把整个spring中涉及的BeanDefinition给存储起来?那么存储在一个什么结构里面呢?那显示是一个Map,存储多个,方便取,key beanName | id value BeanDefinitionHolder。
所以这行代码完成的就是我们注册的功能。

2.2.3.3.3 fireComponentRegistered
image-20230507092213535 发送注册完成的事件,整个的过程我已经做完了,那我通过事件的方式告诉spring容器,spring容器就可以做一些额外的操作了。 我们可以监听这个事件来做一些事情,当我们注册完成之后,可以发起这个事件来做一些后续操作
2.2.3.4 处理beans内嵌
image-20230507100546770

第四个if解决的是内嵌的beans标签
什么叫做内嵌的beans标签呢?
就是beans里面又放了beans。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值