引题
上篇回顾:
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
这行代码执行,spring内部会通过流的方式加载配置文件“spring.xml”,获取到标签集合,然后对两种标签解析。 本篇介绍默认标签的解析流程。
默认标签主流程解析
注:以< bean > 标签解析为例:
DefaultBeanDefinitionDocumentReader 类
163 行-165 行:方法注释:解析文档中根级别的元素:“import”、“alias”、“bean” ...
169 行:判断当前标签的namespace是否属于默认指定的命名空间。
判断逻辑: BeanDefinitionParserDelegate 类:
169 行结束。
170 行:获取到root节点的子节点集合。如下图:
170 行结束。
171 行-174 行:遍历子节点集合,并将root转换为Element对象。
175 行:见169 行逻辑。
176 行:默认标签判断入口。点击进入本类方法
本类标签名常量:
191 行:解析< import > 标签
194 行:解析 < alias > 标签
197 行:解析 < bean > 标签,点击进入本类方法
方法总结:将标签对象转换成 BeanDefinitionHolder 对象,并开始将BD注册到缓存。
302 行-303 行:方法注释,处理给定的 bean 元素,解析 bean 定义并将其注册到注册表。
306 行:将 Element 对象包装成 BeanDefinitionHolder 对象 点击进入 BeanDefinitionParserDelegate 类
BeanDefinitionParserDelegate 类
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 类
方法注释:使用给定的 bean 工厂注册给定的 bean 定义。入参为BDH,之前创建的 DefaultListableBeanFactory。
163 行:获取到beanName。
164 行:用 DefaultListableBeanFactory 工厂注册当前的 BD。
注册逻辑:
DefaultListableBeanFactory 类
类注释: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 定义元数据。
942 行:从 beanDefinitionMap 中获取当前bd,先判断是否已经注册过。
945 行:如果注册过,抛出异常。
972 行:判断当前是否已经有 bean 被实例化过。
AbstractBeanFactory 类
173 行:记录已至少创建一次的 bean 的名称。
1776 行:判断当前有没有bean被创建过。程序第一次运行到这里显示是没有的,返回false。
975 行-979 行:程序已经运行一段时间,当前已经有实例化的bean,走这段逻辑。
985 行:当前还没有 bean 被创建过,程序会走到这里,把当前 BD 存到 beanDefinitionMap 中。
986 行:把当前 bean 的 名称也单独记录到 beanDefinitionNames 集合中。
回到 BeanDefinitionReaderUtils 类的注册BD方法中。此时我们已经将 BD 注册到了 bean工厂(BeanDefinitionRegistry)中。
方便查看,这里再贴一份注册的方法:
164 行:已经完成了BD注册。
166 行:建立别名和id的映射关系。
167 行:获取当前BD的别名集合。
168 - 172 行:循环别名并注册。
SimpleAliasRegistry 类
168 - 172 行结束。
到此,当前 BD 就完成了注册流程。然后回到 DefaultBeanDefinitionDocumentReader 类。
方便查看,这里再贴一份循环标签开始注册BD的方法:
176 行结束:已经完成了对当前循环的 BD 的注册。继续循环注册...
总结
< bean >标签解析就是将一个一个的< bean >标签转换为 BD(BeanDefinition) 对象,转换时将标签里面的配置属性等元素设置到 BD 对象中,然后再将 BD 存入 BD工厂(DefaultListableBeanFactory)的缓存Map(beanDefinitionMap)中。
注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。