侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

Spring IoC自定义标签解析

2022-06-12 星期日 / 0 评论 / 0 点赞 / 92 阅读 / 19015 字

概述自定义标签获取标签的命名空间读取自定义标签处理器标签解析概述本文接着 Spring IoC之存储对象BeanDefinition 一文继续学习,在学习自定义标签的知识时,首先我们先了解一下自定义标

概述自定义标签获取标签的命名空间读取自定义标签处理器标签解析

概述

本文接着 Spring IoC之存储对象BeanDefinition 一文继续学习,在学习自定义标签的知识时,首先我们先了解一下自定义标签的实现,欢迎阅读:Spring自定义标签的实现

自定义标签

parseBeanDefinitions()方法中有这么一段代码:

如果传入的标签不是默认标签,则调用 parseCustomElement(ele)方法,该方法定义如下:

处理过程分为三步:

  1. 获取标签的命名空间
  2. 读取自定义标签处理器
  3. 标签解析

获取标签的命名空间

标签的解析是从命名空间的提起开始的,无论是区分 Spring 中默认标签和自定义标签 还是 区分自定义标签中不同标签的处理器都是以标签所提供的命名空间为基础的,而至于如何提取对应元素的命名空间其实并不需要我们亲内去实现,在 org.w3c.dom.Node 中已经提供了方法供我们直接调用:

String namespaceUri = getNamespaceURI(ele);

在代码调试过程中可以看到此处的数据,如下图所示:

读取自定义标签处理器

根据 namespaceUri 获取 Handler,这个映射关系我们在 Spring.handlers 中已经定义了,所以只需要找到该类,然后初始化返回,最后调用该 Handler 对象的 parse() 方法处理,该方法我们也提供了实现。所以上面的核心就在于怎么找到该 Handler 类。调用方法为

首先 this.readerContext.getNamespaceHandlerResolver()返回了一个 NamespaceHandlerResolver 对象,该对象在 registerBeanDefinitions 中的 createReaderContext()方法设置的,其中涉及到以下方法:

XmlReaderContext 构造函数中最后一个参数就是 NamespaceHandlerResolver 对象,该对象由 getNamespaceHandlerResolver() 提供,如下:

所以 getNamespaceHandlerResolver().resolve(namespaceUri) 调用的就是 DefaultNamespaceHandlerResolver 的 resolve()。如下:

首先调用 getHandlerMappings() 获取所有配置文件中的映射关系 handlerMappings ,该关系为 <命名空间,类路径>,然后根据命名空间 namespaceUri 从映射关系中获取相应的信息,如果为空或者已经初始化了就直接返回,否则根据反射对其进行初始化,同时调用其 init() 方法,最后将该 Handler 对象缓存。 init() 方法主要是将自定义标签解析器进行注册,如我测试代码中的 init()

当得到自定义命名空间处理后会马上执行 namespaceHandler.init() 来进行自定义 BeanDefinitionParser的注册,在这里,你可以注册多个标签解析器。init()中的 registerBeanDefinitionParser 方法 其实就是将映射关系放在一个 Map 结构的 parsers 对象中:private final Map parsers

标签解析

得到了解析器和分析的元素后,Spring 就可以将解析工作委托给自定义解析器去解析了,对于标签的解析使用的是:NamespaceHandler.parse(ele, new ParserContext(this.readerContext, this, containingBd))方法,进入到方法体内:

调用 findParserForElement() 方法获取 BeanDefinitionParser 实例,其实就是获取在 init() 方法里面注册的实例对象。如下:

获取 localName,在上面的例子中就是 : xxx,然后从 Map 实例 parsers 中获取 CarParser 实例对象。返回 BeanDefinitionParser 对象后,调用其 parse(),该方法在 CarParser 中实现:

我们在 CarParser 类中定义了两个方法如下:

自定义的 parse()方法首先定义创建一个 RootBeanDefinition,setBeanClass()方法相当于标签中的 class 属性,通过 element 获取到各个属性填写的值,然后填充到 beanDefinition 的 propertyValues 属性中,用于之后 bean 实例的创建。id 属性还是用来标识标签,最后将 id 和 beanDefinition 一起注册到BeanDefinitionRegistry 中。

至此,自定义标签的解析过程已经分析完成了。其实整个过程还是较为简单:首先会加载 handlers 文件,将其中内容进行一个解析,形成 这样的一个映射,然后根据获取的 namespaceUri 就可以得到相应的类路径,对其进行初始化等到相应的 Handler 对象,调用 parse() 方法,在该方法中根据标签的 localName 得到相应的 BeanDefinitionParser 实例对象,调用 parse() ,该方法定义在 BeanDefinitionParser 的实现类中。对于自定义的 Parser 类,首先需要与 bean 类相关联,这里我们采用的是设置个 beanclass 属性, 最为重要的是 doParse()方法,该方法将标签中填写的属性值,填充到一个新的 BeanDefinition 中,最后将其注册到 BeanDefinitionRegistry 中 。

..
.

广告 广告

评论区