死磕Spring之IoC篇 - BeanDefinition 的解析阶段(XML 文件) (2)

parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法,解析 XML Document 的最顶层的标签,解析出 BeanDefinition 并注册,方法如下:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { // <1> 如果根节点使用默认命名空间,执行默认解析 if (delegate.isDefaultNamespace(root)) { // <1.1> 遍历所有的子节点 NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; // <1.2> 如果该节点使用默认命名空间,执行默认解析 if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } // <1.3> 如果该节点非默认命名空间,执行自定义解析 else { delegate.parseCustomElement(ele); } } } } // <2> 如果根节点非默认命名空间,执行自定义解析 else { delegate.parseCustomElement(root); } }

解析过程大致如下:

如果根节点使用默认命名空间,执行默认解析

遍历所有的子节点

如果该节点使用默认命名空间,执行默认解析,调用 parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 方法

如果该节点非默认命名空间,执行自定义解析,调用 BeanDefinitionParserDelegate#parseCustomElement(Element ele) 方法

如果根节点非默认命名空间,执行自定义解析,调用 BeanDefinitionParserDelegate#parseCustomElement(Element ele) 方法

命名空间是什么?

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.geekbang.thinking.in.spring.ioc.overview" /> <bean> <property value="1"/> <property value="小马哥"/> </bean> </beans>

在 XML 文件中的标签的 xmlns 可以定义默认的命名空间,xmlns:context 定义 context 的命名空间,xsi:schemaLocation 定义了命名空间对应的 XSD 文件(校验 XML 内容)。

上面的 <beans /> 和 <bean> 标签的命名空间为 ,其中 <context:component-scan /> 标签的命名空间为 (不是默认命名空间)

本文主要分析默认命名空间的解析过程,其他命名空间(注解相关)在后面进行分析,基于 Extensible XML authoring 扩展 Spring XML 元素会进入这里,主要是通过 NamespaceHandler 这个接口实现的。例如 Spring 集成 Mybatis 项目中的 <mybatis:scan /> 就是扩展 Spring XML 元素,具体实现在后面分析;Spring 的<context:component-scan /> 最终会通过 ComponentScanBeanDefinitionParser 进行解析。ComponentScanBeanDefinitionParser 是将 @Component 注解标注的类转换成 BeanDefinition 的解析器。

3. parseDefaultElement 方法

parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 方法,处理默认命名空间的节点,方法如下:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // 解析 `<import />` importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // 解析 `<alias />`,将 name 对应的 alias 别名进行注册 processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // 解析 `<bean />` processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // 循环处理,解析 `<beans />` doRegisterBeanDefinitions(ele); } }

解析下面四种标签:

<import /> 标签,例如这么配置:<import resource="dependency-lookup-context.xml"/>,那么这里会获取到对应的 XML 文件,然后进行相同的处理过程

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygpww.html