文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

关于Spring自定义XML schema 扩展的问题(Spring面试高频题)

2024-04-02 19:55

关注

引言

自从SpringBoot时代的到来,去除了Spring的各种繁琐的XML配置,让我们可以腾出双手以便于更加专注的搬砖。记得那时候刚学Spring的时候,每天被Spring的各种XMl配置文件折磨的不行,每引入一个新的框架,最担心的就是jar冲突、哪个配置文件又配的不对、配置文件没有起作用。所以每次搭建好一个项目就把配置文件用小笔记记录下来, 方便下次在整合项目的时候直接copy复制就好。下面我们就以Spring整合dubbo的事例看下


<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <dubbo:application name="demo-provider"/>
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:protocol name="dubbo" port="20890"/>
    <bean id="demoService" class="org.apache.dubbo.samples.basic.impl.DemoServiceImpl"/>
    <dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService"/>
</beans>

上述代码中我们有看到dubbo自定义了一套自己的标签,dubbo:application ,dubbo:registry ,dubbo:protocol,dubbo:service我们心中是不是有点小疑问:这些标签在Spring项目启动的时候是如何被Spring管理的?是怎样被Spring来识别的?如果我们自己随便定义一个标签Spring是否能够识别?我们去翻翻Spring的官网发现这玩意其实就是Spring提供的 XML schema 的扩展支持。只要按照它的步骤来,我们就可以配置任何我们自定义的标签。XML schema 扩展机制是什么?这个也许好多人没听过:

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

我们可以看看官网https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#xml-custom 10.2. XML Schema Authoring 这个是主要介绍它的。

如何实现一个自定义 XML 扩展

官网有介绍,要实现一个自定义的XML Schema 总共需要4步:

编写一个 XML schema 文件描述的你节点元素。

编写一个 NamespaceHandler 的实现类

编写一个或者多个 BeanDefinitionParser 的实现 (关键步骤).

注册上述的 schema 和 handler。

既然只要按照这四步来,那我们就照着这个文档来自己实现一个。

Authoring the Schema

编写一个javajr.xsd 放入项目的resources/META-INF文件夹里面(这个也可以是其他路径)


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:beans="http://www.springframework.org/schema/beans"
            xmlns:tool="http://www.springframework.org/schema/tool"
            xmlns="https://www.javajr.cn/schema/javajr"
            targetNamespace="https://www.javajr.cn/schema/javajr">
 
    <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="website" type="xsd:string" use="required"/>
                    <xsd:attribute name="weixin" type="xsd:string" use="required"/>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

这里我们就定义了一个元素application 里面有两个属性分别为websiteweixin

编写一个 NamespaceHandler


package org.spring.demo.schema;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class MyNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
     // 这个名字也不是随便取的,上面编写xsd的根节点元素的name, <xsd:element name="application">
        registerBeanDefinitionParser("application", new MyBeanDefinitionParser());
    }
}

这个NamespaceHandler 就是将一个 XML 节点解析成 IOC 容器中的一个实体类。也就是说相当于在xml里面的配置的对象,通过Spring ioc 容器管理起来了

编写 BeanDefinitionParser 的实现类


package org.spring.demo.schema;
import org.spring.demo.domain.JavajrDomain;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
 
public class MyBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
 
    @Override
    protected Class<?> getBeanClass(Element element) {
        return JavajrDomain.class;
    }
    @Override
    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        // this however is an optional property
        String website = element.getAttribute("website");
        if (StringUtils.hasText(website)) {
            bean.addPropertyValue("website",website);
        }
        String weiXin = element.getAttribute("weixin");
        if (StringUtils.hasText(weiXin)) {
            bean.addPropertyValue("weixin",weiXin);
        }
    }
}

上面在这个实现类只是简单的做了一个赋值操作,你如果需要有自己的逻辑业务也可以自行来实现。上面还有一个JavajrDomain这个实体类就不贴代码,就一个简单的javabean里面包含了两个属性weixin和website。

注册schema组件

最后在resources/META-INF目录下添加两个配置文件(spring.handler和spring.schema):

resources/META-INF/spring.handlers

https\://www.javajr.cn/schema/javajr=org.spring.demo.schema.MyNamespaceHandler

resources/META-IN/spring.schemas

https\://www.javajr.cn/schema/javajr.xsd=META-INF/javajr.xsd

在这个地方的时候我们其实可以以版本号来进行命名,方便我们可以使用多个不同的版本,Spring-beans 就是这么玩的。

测试自定义schema

resources 目录下新建一个applicationContext.xml文件

这个文件就是使用下我们我们自己自定义的schema,这个文件需要注意的就是上面标红的这几行,一般如果我们有引入过第三方的框架,比如mq、或者dubbo等它们都有自定义的这些玩意。

编写一个启动类


public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        JavajrDomain bean = ctx.getBean(JavajrDomain.class);
        System.out.println(bean.toString());
    }

我们可以看到控制台输出


JavajrDomain{weixin='javajr8', website='javajr.cn'}

到这里我们自己实现的一个 XML schema 就完成了,是不是很简单,只要照着官方文档撸就可以了。照着撸的过程可能有几个小细节需要注意下引入 XML schema 的时候需要注意下空格,或者一些特殊符号。上述代码已经提交到了gitee上https://gitee.com/javajr/spring-schema-demo 感兴趣的朋友可以直接下载下来run下,不过还是不建议这么玩,最好还是自己动手去尝试下,毕竟也就四步,照着文档来。

Dubbo 中的 XML schema 扩展

在文章开始的时候我们有介绍dubbo 自定义的XML schema ,下面我们一起打开dubbo源码看看它是如何来实现的,看下面这个截图,也是按照那四步来的。

SpringBoot的starter

现在有了SpringBoot 之后以前用这个 XML schema配置的框架,大多数都会有对应的starter来进行封装,starter的使用比起 XML schema的使用还是简单多了,开箱即用,无需编写很多的配置文件。如果不是很清楚SpringBootstarter的推荐去看看这两篇文章《面试高频题:springBoot自动装配的原理你能说出来吗?》《保姆级教程,手把手教你实现一个SpringBoot的starter》。

总结

虽然现在XML schema 扩展用的不多了,但是应该也还有比较老的项目在使用吧,如果还是比较老的项目,需要引入一个什么样的框架,我们至少需要知道需要怎么去引入,网上虽然有很多文章可以借鉴,但是我们也应该知其然知其所以然。而不是直接把配置文件单纯的copy过来。我们应该知道为啥需要copy这个xsd,为什么没有这个xsdidea不糊识别会报错。

以上就是关于Spring自定义XML schema 扩展的问题(Spring面试高频题)的详细内容,更多关于Spring XML schema 扩展的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯