前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Spring中的XML schema扩展机制

Spring中的XML schema扩展机制

作者头像
用户5397975
发布于 2019-10-13 07:05:59
发布于 2019-10-13 07:05:59
94500
代码可运行
举报
文章被收录于专栏:咖啡拿铁咖啡拿铁
运行总次数:0
代码可运行

前言

很久没有写关于 Spring 的文章了,最近在系统梳理 Dubbo 代码的过程中发现了 XML schema 这个被遗漏的知识点。由于工作中使用 SpringBoot 比较多的原因,几乎很少接触 XML,此文可以算做是亡羊补牢,另一方面,也为后续的 Dubbo 源码解析做个铺垫。

XML schema 扩展机制是啥?这并不是一块很大的知识点,翻阅一下 Spring 的文档,我甚至没找到一个贯穿上下文的词来描述这个功能, XMLSchemaAuthoring 是文档中对应的标题,简单来说:

Spring 为基于 XML 构建的应用提供了一种扩展机制,用于定义和配置 Bean。 它允许使用者编写自定义的 XML bean 解析器,并将解析器本身以及最终定义的 Bean 集成到 Spring IOC 容器中。

Dubbo 依赖了 Spring,并提供了一套自定义的 XML 标签, <dubbo:application> , <dubbo:registry> , <dubbo:protocol>, <dubbo:service>。作为使用者,大多数人只需要关心这些参数如何配置,但不知道有没有人好奇过,它们是如何加载进入 Spring 的 IOC 容器中被其他组件使用的呢?这便牵扯出了今天的主题:Spring 对 XML schema 的扩展支持。

自定义 XML 扩展

为了搞懂 Spring 的 XML 扩展机制,最直接的方式便是实现一个自定义的扩展。实现的步骤也非常简单,分为四步:

  1. 编写一个 XML schema 文件描述的你节点元素。
  2. 编写一个 NamespaceHandler 的实现类
  3. 编写一个或者多个 BeanDefinitionParser 的实现 (关键步骤).
  4. 注册上述的 schema 和 handler。

我们的目的便是想要实现一个 kirito XML schema,我们的项目中可以自定义 kirito.xml,在其中会以 kirito 为标签来定义不同的类,并在最终的测试代码中验证这些声明在 kirito.xml 的类是否被 Spring 成功加载。大概像这样,是不是和 dubbo.xml 的格式很像呢?

动手实现

有了明确的目标,我们逐步开展工作。

1 编写kirito.xsd

resources/META-INF/kirito.xsd

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.cnkirito.moe/schema/kirito"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:beans="http://www.springframework.org/schema/beans"
            targetNamespace="http://www.cnkirito.moe/schema/kirito"><xsd:import namespace="http://www.springframework.org/schema/beans"/>

    <xsd:element name="application"><xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="name" type="xsd:string" use="required"/>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="service"><xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="name" type="xsd:string" use="required"/>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>


</xsd:schema>

① 注意这里的 targetNamespace="http://www.cnkirito.moe/schema/kirito" 这便是之后 kirito 标签的关键点。

② kirito.xsd 定义了两个元素: application 和 service,出于简单考虑,都只有一个 name 字段。

schema 的意义在于它可以和 eclipse/IDEA 这样智能化的集成开发环境形成很好的搭配,在编辑 XML 的过程中,用户可以获得告警和提示。 如果配置得当,可以使用自动完成功能让用户在事先定义好的枚举类型中进行选择。

2 编写KiritoNamespaceHandler
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class KiritoNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        super.registerBeanDefinitionParser("application", new KiritoBeanDefinitionParser(ApplicationConfig.class));
        super.registerBeanDefinitionParser("service", new KiritoBeanDefinitionParser(ServiceBean.class));
    }

}

完成 schema 之后,还需要一个 NamespaceHandler 来帮助 Spring 解析 XML 中不同命名空间的各类元素。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<kirito:application name="kirito"/>
<dubbo:application name="dubbo"/>
<motan:application name="motan"/>

不同的命名空间需要不同的 NamespaceHandler 来处理,在今天的示例中,我们使用 KiritoNamespaceHandler 来解析 kirito 命名空间。KiritoNamespaceHandler 继承自 NamespaceHandlerSupport 类,并在其 init() 方法中注册了两个 BeanDefinitionParser ,用于解析 kirito 命名空间/kirito.xsd 约束中定义的两个元素:application,service。BeanDefinitionParser 是下一步的主角,我们暂且跳过,将重心放在父类 NamespaceHandlerSupport 之上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface NamespaceHandler {
   void init();
   BeanDefinition parse(Element element, ParserContext parserContext);
   BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);
}

NamespaceHandlerSupport 是 NamespaceHandler 命名空间处理器的抽象实现,我粗略看了NamespaceHandler 的几个实现类,parse 和 decorate 方法可以完成元素节点的组装并通过 ParserContext 注册到 Ioc 容器中,但实际我们并没有调用这两个方法,而是通过 init() 方法注册 BeanDefinitionParser 来完成解析节点以及注册 Bean 的工作,所以对于 NamespaceHandler,我们主要关心 init 中注册的两个 BeanDefinitionParser 即可。

3 编写KiritoBeanDefinitionParser

在文章开始我们便标记到 BeanDefinitionParser 是最为关键的一环,每一个 BeanDefinitionParser 实现类都负责一个映射,将一个 XML 节点解析成 IOC 容器中的一个实体类。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class KiritoBeanDefinitionParser implements BeanDefinitionParser {

    private final Class<?> beanClass;

    public KiritoBeanDefinitionParser(Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        String name = element.getAttribute("name");
        beanDefinition.getPropertyValues().addPropertyValue("name", name);
        parserContext.getRegistry().registerBeanDefinition(name, beanDefinition);
        return beanDefinition;
    }

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        return parse(element, parserContext, beanClass);
    }

}

由于我们的实体类是非常简单的,所以不存在很复杂的解析代码,而实际项目中,往往需要大量的解析步骤。parse 方法会解析一个个 XML 中的元素,使用 RootBeanDefinition 组装成对象,并最终通过 parserContext 注册到 IOC 容器中。

至此,我们便完成了 XML 文件中定义的对象到 IOC 容器的映射。

4 注册schema和handler

最后一步还需要通知 Spring,告知其自定义 schema 的所在之处以及对应的处理器。

resources/META-INF/spring.handlers

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
http\://www.cnkirito.moe/schema/kirito=moe.cnkirito.sample.xsd.KiritoNamespaceHandler

resources/META-INF/spring.schemas

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
http\://www.cnkirito.moe/schema/kirito/kirito.xsd=META-INF/kirito.xsd

没有太多可以说的,需要遵守 Spring 的约定。

至此一个自定义的 XML schema 便扩展完成了,随后来验证一下。

验证扩展

我们首先定义好 kirito.xml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:kirito="http://www.cnkirito.moe/schema/kirito"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans
                                http://www.springframework.org/schema/beans/spring-beans.xsd
                                http://www.cnkirito.moe/schema/kirito
                                http://www.cnkirito.moe/schema/kirito/kirito.xsd">

    <kirito:application name="kirito-demo-application"/>

    <kirito:service name="kirito-demo-service"/>

</beans>

使用 Spring 去加载它,并验证 IOC 容器中是否存在注册成功的 Bean。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@SpringBootApplication
@ImportResource(locations = {"classpath:kirito.xml"})
public class XmlSchemaAuthoringSampleApplication {

   public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(XmlSchemaAuthoringSampleApplication.class, args);
        ServiceBean serviceBean = applicationContext.getBean(ServiceBean.class);
        System.out.println(serviceBean.getName());
        ApplicationConfig applicationConfig = applicationContext.getBean(ApplicationConfig.class);
        System.out.println(applicationConfig.getName());
    }
}

观察控制台的输出:

kirito-demo-service kirito-demo-application

一个基础的基于 XML schema 的扩展便完成了。

Dubbo中的XML schema扩展

最后我们以 Dubbo 为例,看看一个成熟的 XML schema 扩展是如何被应用的。

刚好对应了四个标准的扩展步骤,是不是对 XML 配置下的 Dubbo 应用有了更好的理解了呢?

顺带一提,仅仅完成 Bean 的注册还是不够的,在“注册”的同时,Dubbo 还进行了一系列其他操作如:暴露端口,开启服务器,完成注册中心的注册,生成代理对象等等行为,由于不在本文的范围内,后续的 Dubbo 专题会专门介绍这些细节,本文便是了解 Dubbo 加载流程的前置文章了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-09-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 咖啡拿铁 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制
在 Dubbo 中,可以使用 XML 配置相关信息,也可以用来引入服务或者导出服务。配置完成,启动工程,Spring 会读取配置文件,生成注入 相关 Bean。那 Dubbo 如何实现自定义 XML 被 Spring 加载读取?
andyxh
2019/09/10
5650
缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制
【DUBBO】 Schema解析Spring扩展机制集成Spring
dubbo是如何做到与spring集成的?这都依赖于Spring提供的XML Schema可扩展机制,用户可以自定义XML Schema文件,并自定义XML Bean解析器,并集成到SpringIOC容器中。 创建自定义扩展,主要有以下步骤: 1、创建XML Schema 文件,描述自定义的合法构建模块,也就是xsd文件,主要用于定义数据约束; 2、自定义个处理器类,并实现NamespaceHandler接口,在里面注册各个标签对应的BeanDefinitionParser; 3、自定义一个或多个解析器,实现BeanDefinitionParser接口,用于定义Bean的解析逻辑;
spilledyear
2018/12/19
1.1K0
Spring面试高频题如何:自定义XML schema 扩展
自从SpringBoot时代的到来,去除了Spring的各种繁琐的XML配置,让我们可以腾出双手以便于更加专注的搬砖。
java金融
2021/05/17
6470
让Spring在你面前裸奔(三)-扩展篇之自定义xml标签
这个扩展篇,是基于我的深入理解Spring Ioc 系列写的,主要讲的是spring 装载解析bean这个过程中可以扩展的地方,可能你之前知道一些Spring 中的扩展点,但是却又缺乏一个整体的认识,那么相信我,看完了整个扩展篇,你就能把之前的不熟练的姿势运用的很熟练,并且还能学会很多新的姿势。
JAVA葵花宝典
2020/06/04
8450
让Spring在你面前裸奔(三)-扩展篇之自定义xml标签
Spring 实现自定义 bean 的扩展
Spring mvc 提供了扩展 xml 的机制,用来编写自定义的 xml bean ,例如 dubbo 框架,就利用这个机制实现了好多的 dubbo bean,比如 <dubbo:applicati
古时的风筝
2018/01/08
9720
Spring 实现自定义 bean 的扩展
基于Spring的可扩展Schema进行开发自定义配置标签支持
  最近和朋友一起想开发一个类似alibaba dubbo的功能的工具,其中就用到了基于Spring的可扩展Schema进行开发自定义配置标签支持,通过上网查资料自己写了一个demo.今天在这里进行和大家分享,也记录下方便以后复习备忘。
阿豪聊干货
2018/08/09
3750
基于Spring的可扩展Schema进行开发自定义配置标签支持
Spring5 扩展篇之自定义xml标签
首先这个文件最好建立在静态资源resource文件夹下,我为了方便都将文件建立在了resource/META-INF下了,包括spring.handlers和spring.schemas这三个文件都在该目录下:
@派大星
2023/06/28
3090
Spring5 扩展篇之自定义xml标签
【死磕 Spring】----- IOC 之解析自定义标签
在博客 【死磕Spring】----- IOC 之 注册 BeanDefinition 中提到:获取 Document 对象后,会根据该对象和 Resource 资源对象调用 registerBeanDefinitions() 方法,开始注册 BeanDefinitions 之旅。在注册 BeanDefinitions 过程中会调用 parseBeanDefinitions() 开启 BeanDefinition 的解析过程。在该方法中,它会根据命名空间的不同调用不同的方法进行解析,如果是默认的命名空间,则调用 parseDefaultElement() 进行默认标签解析,否则调用 parseCustomElement() 方法进行自定义标签解析。前面 6 篇博客都是分析默认标签的解析工作,这篇博客分析自定义标签的解析过
用户1655470
2018/11/23
6390
聊聊自定义SPI如何使用自定义标签注入到spring容器中
之前我们聊过自定义的SPI如何与spring进行整合,今天我们就来聊下如何通过自定义标签将spi对象注入到spring容器中
lyb-geek
2021/11/25
6610
聊聊自定义SPI如何使用自定义标签注入到spring容器中
手写类似dubbo的rpc框架第一章《自定义配置xml》
案例介绍 本案例通过三个章节来实现一共简单的rpc框架,用于深入学习rpc框架是如何通信的,当前章节主要介绍如何自定义xml文件并进行解析。想解析自定义的xml首先定义自己的xsd文件,并且实现spring的NamespaceHandlerSupport、BeanDefinitionParser,两个方法进行处理。
小傅哥
2020/07/14
2960
spring的自定义标签都不会?你可能只学到了spring的皮毛
通常我们在applicationContext.xml文件中使用spring的标签时,会发现spring默认支持的只有5种,如图所示
苏三说技术
2020/10/15
1.3K0
spring的自定义标签都不会?你可能只学到了spring的皮毛
dubbo基于spring运行原理解析
dubbo是基于spring构建和运行的,兼容spring配置。这篇说说dubbo基于spring的过程。 dubbo首先利用了从spring2.0开始的一个特性,Extensible XML authoring,扩展spring了标签功能。 关于如何利用spring扩展自己的标签,可以参考下官方介绍 https://docs.spring.io/spring/docs/3.2.18.RELEASE/spring-framework-reference/htmlsingle/#extensible-xml 根据文档的说法,需要如下4步: 1,编写xml,描述需要扩展的标签的配置属性,dubbo实现放在jar包META-INF/dubbo.xsd文件里 同时通过编写META-INF/spring.handlers文件,提供给spring,内容如下 http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd xsd文件也很好编写阅读,里面有继承和嵌套的概念。 2,写一个NamespaceHandler接口实现类,dubbo的实现类是DubboNamespaceHandler 同时通过编写META-INF/spring.schemas文件,提供给spring,内容如下: http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler 3,编写一个(或者多个)BeanDefinitionParser实现类,用来解析扩展的元素,dubbo实现类是DubboBeanDefinitionParser, 这个类也是真正的需要自己处理的代码所在。 4,把以上组件注册给spirng,这个dubbo其实在DubboNamespaceHandler类里。
技术蓝海
2018/04/26
2K0
dubbo基于spring运行原理解析
Spring的BeanDefinition解析
在Spring生成bean的过程中,我们提到了Spring会先加载配置文件中的BeanDefinition,然后才会getBean。像普通的<bean>标签,我们也能写一个简单的解析工具将它转换为BeanDefinition,而像<context:component-scan>这样非基本的bean定义又是怎么解析的呢?
zhangheng
2020/04/29
7590
Elastic-Job2.1.5源码-自定义Spring标签与Spring 依赖注入无缝整合
大家好,本文给大家简单介绍一下Elastic-Job 是如何自定义标签与与Spring 依赖注入无缝整合
宋小生
2022/12/14
6790
基于Spring可扩展Schema提供自定义配置支持(spring配置文件中 配置标签支持)
原文链接:http://www.cnblogs.com/jifeng/archive/2011/09/14/2176599.html (点击阅读原文前往)
java达人
2018/12/18
9250
基于Spring可扩展Schema提供自定义配置支持(spring配置文件中 配置标签支持)
Spring源码分析(二)Spring怎么扩展解析xml接口的
https://blog.csdn.net/bingduanlbd/article/details/38770685
石臻臻的杂货铺[同名公众号]
2021/07/14
2700
Spring MVC介绍(三)之 Annotation解析以及完整的执行流程
工作中对于Spring MVC我们最常用的还是使用注解的方式,那么对于注解Spring MVC的如何处理的?
zoro
2019/04/11
9990
Dubbo系列笔记之XML配置文件解析流程
Spring通过XML解析程序将其解析为DOM树,通过NamespaceHandler指定对应的Namespace的BeanDefinitionParser将其转换成BeanDefinition。再通过Spring自身的功能对BeanDefinition实例化对象。Dubbo做的只是实现了NamespaceHandler解析成BeanDefinition。
用户5546570
2020/11/12
1.1K0
Dubbo系列笔记之XML配置文件解析流程
源码分析Dubbo前置篇-寻找注册中心、服务提供者、服务消费者功能入口
上面通过dubbo提供的dubbo:application、dubbo:registry、dubbo:protocol、dubbo:provider、dubbo:service分别定义dubbo应用程序名、注册中心、协议、服务提供者参数默认值、服务提供者,这些配置后面的实现原理是什么呢?是如何启动并发挥相关作用的呢?
丁威
2019/06/10
1.2K0
源码分析Dubbo前置篇-寻找注册中心、服务提供者、服务消费者功能入口
Spring源码初探-IOC(2)-Bean的初始化-自定义标签解析
前面一文介绍的是Spring对于DefaultElement的解析,例如bean/import/alias等,但是在Spring体系中也存在很多扩展标签,例如事务、aop等非Default标签。按一般的套路通常是先介绍在Spring体系下如何在XML配置文件中自定义标签,本文先介绍Spring对于自定义标签的解析过程,在知道了Spring怎么“读”XML配置之后,写其能“读懂”的配置就显得非常自然了。
LNAmp
2018/09/05
4110
Spring源码初探-IOC(2)-Bean的初始化-自定义标签解析
推荐阅读
相关推荐
缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制
更多 >
LV.0
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验