首页 > 编程语言 >(三)Spring源码解析:自定义标签解析

(三)Spring源码解析:自定义标签解析

时间:2023-05-23 11:04:04浏览次数:29  
标签:... 自定义 标签 源码 实例 解析 方法

一、使用示例

步骤1:创建User实体

(三)Spring源码解析:自定义标签解析_配置文件

步骤2:定义一个XSD文件描述组件内容

(三)Spring源码解析:自定义标签解析_spring_02

步骤3:创建BeanDefinitionParser接口的实现类,用来解析XSD文件中的定义和组件定义

(三)Spring源码解析:自定义标签解析_配置文件_03

步骤4:创建NamespaceHandlerSupport实现类,目的是将组件注册到Spring容器中

(三)Spring源码解析:自定义标签解析_spring_04

步骤5:编写spring.handlersspring.schemas文件,默认位置是/META-INF目录下

(三)Spring源码解析:自定义标签解析_配置文件_05

步骤6:在配置文件oldbean.xml中引入对应的命名空间以及XSD之后,就可以配置<myname:user ... />

(三)Spring源码解析:自定义标签解析_自定义标签_06

步骤7:进行测试

(三)Spring源码解析:自定义标签解析_自定义标签_07

二、源码解析

在第2讲中,我们已经介绍了关于默认标签的解析过程。那么我们还是需要将视角在回到parseBeanDefinitions(...)方法上来,从下图源码截图中我们可以看出来,我们首先是来判断rootroot的子节点是否是默认表空间,即:通过delegate.isDefaultNamespace(...)来进行判断:

如果是默认表空间】执行默认标签解析——delegate.parseDefaultElement(ele, delegate);
如果不是默认表空间】则执行自定义标签解析——delegate.parseCustomElement(ele);

(三)Spring源码解析:自定义标签解析_配置文件_08

下面我们来看一下parseCustomElement(...)方法的具体实现,具体来说有如下3个步骤:

首先】获得namespaceUri,此处是通过org.w3c.dom.Node中的getNamespaceURI()�方法进行获取的;
其次】获得解析该自定义标签的NamespaceHandler实现类。
最后】调用该实现类的parse(...)方法进行解析操作。

(三)Spring源码解析:自定义标签解析_自定义标签_09

2.1> getNamespaceURI(ele)方法解析

此方法是用于获得namespaceUri,此处是通过org.w3c.dom.Node中的getNamespaceURI()方法进行获取的,以使用示例中为例,将会返回的**namespaceUri=“www.muse.com/schema/user…

(三)Spring源码解析:自定义标签解析_spring_10

2.2> resolve(namespaceUri)方法解析

此方法是用来获得解析该自定义标签的NamespaceHandler实现类,为下图中红框处代码:

(三)Spring源码解析:自定义标签解析_spring_11

在此处的this.readerContext.getNamespaceHandlerResolver()方法中,实际会返回DefaultNamespaceHandlerResolver实例对象。

(三)Spring源码解析:自定义标签解析_自定义标签_12

上面我们了解了DefaultNamespaceHandlerResolver实例对象的创建过程之后,那么下面我们就来分析一下它的resolve(namespaceUri)这个方法的内部实现,下面是该方法的源码部分:

(三)Spring源码解析:自定义标签解析_自定义标签_13

getHandlerMappings()方法中,我们获得了系统加载的所有NamespaceHandler实例对象的映射,映射关系为:key=urivalue=NamespaceHandler实现类。但是,如果我们发现加载的handlerMappings等于null,那么我们就需要去加载META-INF/spring.handlers文件中的配置信息,将其生成NamespaceHandler实例对象的映射。所以,综上所示,getHandlerMappings()方法的主要功能就是读取spring.handlers的配置文件并将配置文件缓存在map中。

(三)Spring源码解析:自定义标签解析_自定义标签_14

那么以我们的演示例子来说,handlerMappings中是包含了11xxxNamespaceHander实例对象的映射关系的,在下图中,红框部分就是我们自定义的UserNamespaceHandler

(三)Spring源码解析:自定义标签解析_自定义标签_15

那么在调用 namespaceHandler.init() 方法的时候,其实调用的是UserNamespaceHandler实例的init()方法,该方法是我们自己实现的。如下图所示:

(三)Spring源码解析:自定义标签解析_spring_16

当我们调用 handlerMappings.put(namespaceUri, namespaceHandler) 方法时,那么就将原本String类型的value值“com.muse.springbootdemo.UserNamespaceHandler”,替换为UserNamespaceHandler实例对象了。如下图所示:

(三)Spring源码解析:自定义标签解析_配置文件_17

2.3> parse(...)方法解析

下面我们再来看一下的parse(...)方法,该方法是用来进行自定义标签的解析操作

(三)Spring源码解析:自定义标签解析_自定义标签_18

parse(...)方法中我们可以看到,首先是通过findParserForElement(element, parserContext)方法来找到localName对应的解析器。以我们上面的示例为例,我们在oldbean.xml中配置的是<myname:user id="user" name="muse" email="[email protected]"/>,那么获得了localName就等于“user”。由于我们在UserNamespaceHandler类中已经配置了userUserBeanDefinitionParser实例对象的对应关系,所以parser就拿它作为方法的返回值。具体详情,请见下图所示:

(三)Spring源码解析:自定义标签解析_配置文件_19

在上面的代码逻辑中,我们已经获得到了parser示例对象(UserBeanDefinitionParser实例对象),那么我们通过调用parser对象的 parser(element, parserContext) 方法对自定义标签执行解析操作。下面是该方法涉及的源码部分:

(三)Spring源码解析:自定义标签解析_配置文件_20

我们在上面可以看到,对自定义标签进行解析是在parseInternal(element, parserContext)方法中执行的,

(三)Spring源码解析:自定义标签解析_自定义标签_21

doParse(element, parserContext, builder)方法中,执行了真正的自定义标签解析逻辑,那么既然是自定义标签,是无法通过Spring进行解析的,而是需要我们自己提供自定义解析类XxxBeanDefinitionParser来实现doParse(...)方法的,具体如下所示:

(三)Spring源码解析:自定义标签解析_配置文件_22

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享

更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

标签:...,自定义,标签,源码,实例,解析,方法
From: https://blog.51cto.com/u_15003301/6330116

相关文章

  • LLvm 源码结构及测试基础
    LLvm源码结构及测试基础https://www.cnblogs.com/ainima/archive/2013/02/27/6331983.htmlhttps://www.cnblogs.com/ainima/archive/2013/02/27/6331985.htmlhttps://www.cnblogs.com/wujianming-110117/p/17128814.html......
  • drf——自定义权限
    第一步:创建自定义权限首先,需要创建自定义权限类以实现企业黑名单功能。在你的permissions.py文件中创建一个新的类,例如:fromrest_frameworkimportpermissionsclassBlacklistPermission(permissions.BasePermission):message='Youraccounthasbeenblacklisted.'......
  • pytest + yaml 框架 -29.模板过滤器语法与自定义过滤器使用
    前言v1.2.6版本支持模板过滤器语法的使用,并且可以自定义过滤器了。针对有同学提到上个接口返回一个id值,下个接口引用变量的时候需要根据这个值做一些运算,比如在引用的结果加1.jinja2是可以支持模板过滤器语法的,本篇介绍下模板过滤器的相关使用.v1.2.6版本主要更新以下几点1......
  • Abp Vnext 动态(静态)API客户端源码解析
    根据以往的经验,通过接口远程调用服务的原理大致如下:服务端:根据接口定义方法的签名生成路由,并暴露Api。客户端:根据接口定义方法的签名生成请求,通过HTTPClient调用。这种经验可以用来理解ABPVNext自动API的方式,但如果不使用自动API并且控制器定义了路由的情况下,远程调用的路......
  • delphi RTC 解析statucode 问题
    开源的版本也一样会。rtcinfo.pas,以下的解析 StatusCode 有问题,如果服务器返回的是“HTTP/1.1200” 后面没有状态文本。会解析不到 状态码,这里应该按标准格式来,协议 空格 状态码 空格 状态文本一个一个解析才对,但是RTC 认为状态码、文本是要一起有的。例子:同一个请......
  • Qt编写视频监控系统74-悬浮工具栏(半透明/上下左右位置/自定义按钮)
    一、前言在监控系统中一般在视频实时预览的时候,希望提供一个悬浮工具条,可以显示一些提示信息比如分辨率、码率、帧率,提供一堆快捷操作按钮,可以录像、抓拍、云台控制、关闭等操作,参考了国内很多监控厂商客户端软件,总结下来基本就是悬浮条可以半透明悬浮在通道窗体上,也有少部分是固......
  • .Net6自定义拦截器
    .Net6自定义拦截器拦截器是Aop(面向切面编程)的思想指的是不改变原代码封装的前提下去实现更多功能这里通过.net的特性(给一个目标对象添加一段配置信息)的方式去实现拦截器功能新建一个特性namespaceCorePolly{publicclassTestAttribute:Attribute{publ......
  • CAN报文解析
    CAN报文解析 一、获得CAN报文的过程准备软硬件环境,硬件周立功CAN卡,软件使用ZLGCANTest,安装在电脑上;通过CAN卡连接整车CAN或者调试端口,通过软件交互界面获取CAN报文。二、CAN2.0B报文基本格式接收到的报文,是一串十六进制的字符,而报文格式定义和位数是按照二进制定义的。29位......
  • goframe API 自定义接口返回值处理
    前言goframe默认使用了中间键ghttp.MiddlewareHandlerResponse,HTTPServer的数据返回通过ghttp.Response对象实现,ghttp.Response对象实现了标准库的http.ResponseWriter接口。数据输出使用Write*相关方法实现,并且数据输出采用了Buffer机制,因此数据的处理效率比较高......
  • drf——反序列化校验源码(了解)、断言、drf之请求和响应、视图之两个视图基类
    1.模块与包#模块与包 模块:一个py文件被别的py文件导入使用,这个py文件称之为模块,运行的这个py文件称之为脚本文件包:一个文件夹下有__init__.py#模块与包的导入问题'''1.导入模块有相对导入和绝对导入,绝对导入的路径是从环境变量开始的2.导入任何模块,如果......