【spring源码-2】xml解析(中)默认标签解析

272 阅读5分钟

上一篇 【spring源码-1】xml解析(上)

引题

上篇回顾:

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

这行代码执行,spring内部会通过流的方式加载配置文件“spring.xml”,获取到标签集合,然后对两种标签解析。 本篇介绍默认标签的解析流程。

默认标签主流程解析

注:以< bean > 标签解析为例:

DefaultBeanDefinitionDocumentReader 类

image.png 163 行-165 行:方法注释:解析文档中根级别的元素:“import”、“alias”、“bean” ...


169 行:判断当前标签的namespace是否属于默认指定的命名空间。
判断逻辑: BeanDefinitionParserDelegate 类: image.png image.png 169 行结束。


170 行:获取到root节点的子节点集合。如下图: image.png

170 行结束。


171 行-174 行:遍历子节点集合,并将root转换为Element对象。
175 行:见169 行逻辑。


176 行:默认标签判断入口。点击进入本类方法

本类标签名常量: image.png image.png 191 行:解析< import > 标签
194 行:解析 < alias > 标签
197 行:解析 < bean > 标签,点击进入本类方法

image.png 方法总结:将标签对象转换成 BeanDefinitionHolder 对象,并开始将BD注册到缓存。

302 行-303 行:方法注释,处理给定的 bean 元素,解析 bean 定义并将其注册到注册表。


306 行:将 Element 对象包装成 BeanDefinitionHolder 对象 点击进入 BeanDefinitionParserDelegate 类

BeanDefinitionParserDelegate 类

image.png image.png 515 行:创建一个BD(GenericBeanDefinition) 对象
517 行:将 bean 标签的属性值到 BD 对象的属性上。
520 行:解析 bean 标签中的 < meta > 标签。
521 行:解析 bean 标签中的 < lookup-method > 标签。
522 行:解析 bean 标签中的 < replaced-method > 标签。
524 行:解析 bean 标签中的 < constructor-arg > 标签。
525 行:解析 bean 标签中的 < property > 标签。


308 行:装饰者模式
311 行:注册最终的装饰实例

BeanDefinitionReaderUtils 类

image.png 方法注释:使用给定的 bean 工厂注册给定的 bean 定义。入参为BDH,之前创建的 DefaultListableBeanFactory。
163 行:获取到beanName。


164 行:用 DefaultListableBeanFactory 工厂注册当前的 BD。
注册逻辑:

DefaultListableBeanFactory 类

image.png image.png 类注释:Spring 对ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的默认实现:一个基于 bean 定义元数据的成熟 bean 工厂,可通过后处理器扩展。
类属性定义如下:
140 行:从序列化 id 映射到工厂实例。
144 行:此工厂的可选 ID,用于序列化目的。
148 行:是否允许重新注册具有相同名称的不同定义。
151 行:即使对于lazy-init bean,是否也允许加载急切类。
154 行:依赖列表和数组的可选 OrderComparator。
158 行:用于检查 bean 定义是否是自动装配候选者的解析器。
161 行:从依赖类型映射到相应的自动装配值。
164 行:bean 定义对象的映射,以 bean 名称为键。
167 行:从 bean 名称映射到合并的 BeanDefinitionHolder。
170 行:单例和非单例 bean 名称的映射,以依赖类型为键。
173 行:单例 bean 名称映射,以依赖类型为键。
176 行:bean 定义名称列表,按注册顺序排列。
179 行:手动注册的单例名称列表,按注册顺序排列。
182 行:在冻结配置的情况下缓存的 bean 定义名称数组。
186 行:是否可以为所有 bean 缓存 bean 定义元数据。

image.png image.png 942 行:从 beanDefinitionMap 中获取当前bd,先判断是否已经注册过。
945 行:如果注册过,抛出异常。


972 行:判断当前是否已经有 bean 被实例化过。

AbstractBeanFactory 类

image.png image.png 173 行:记录已至少创建一次的 bean 的名称。
1776 行:判断当前有没有bean被创建过。程序第一次运行到这里显示是没有的,返回false。


975 行-979 行:程序已经运行一段时间,当前已经有实例化的bean,走这段逻辑。 985 行:当前还没有 bean 被创建过,程序会走到这里,把当前 BD 存到 beanDefinitionMap 中。
986 行:把当前 bean 的 名称也单独记录到 beanDefinitionNames 集合中。


回到 BeanDefinitionReaderUtils 类的注册BD方法中。此时我们已经将 BD 注册到了 bean工厂(BeanDefinitionRegistry)中。
方便查看,这里再贴一份注册的方法:

image.png 164 行:已经完成了BD注册。
166 行:建立别名和id的映射关系。
167 行:获取当前BD的别名集合。


168 - 172 行:循环别名并注册。

SimpleAliasRegistry 类

image.png 168 - 172 行结束。


到此,当前 BD 就完成了注册流程。然后回到 DefaultBeanDefinitionDocumentReader 类。
方便查看,这里再贴一份循环标签开始注册BD的方法:
image.png 176 行结束:已经完成了对当前循环的 BD 的注册。继续循环注册...

总结

< bean >标签解析就是将一个一个的< bean >标签转换为 BD(BeanDefinition) 对象,转换时将标签里面的配置属性等元素设置到 BD 对象中,然后再将 BD 存入 BD工厂(DefaultListableBeanFactory)的缓存Map(beanDefinitionMap)中。

注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。

下一篇【spring源码-3】xml解析(下)自定义标签解析