基于Spring的扩展Schema配置

本文介绍了为何需要自定义Spring Schema,以及如何通过设计配置属性、编写XSD文件、实现NamespaceHandler和BeanDefinitionParser来扩展Spring的Schema。通过一个具体的案例,详细阐述了从设计到实现的完整过程,并提出了在Schema配置中遇到的问题,如xmlns和targetNamespace的区别以及Spring查找Schema的规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简述

为什么需要自定义Schema?

很多时候我们在使用Spring的过程中会定义一些配置,最简单的比方说定义< bean,使用< aop或者< mvc标签,用过dubbo的小伙伴可能还会用很多的< dubbo:service这样的配置,通常这样的文件要求开发者按照特定的格式、特定的标签去配置需要的内容,这样的文件结构有很多好处:

  • 可更容易地描述允许的文档内容
  • 可更容易地验证数据的正确性
  • 可更容易地定义数据约束(data facets)
  • 可更容易地定义数据模型(或称数据格式)
  • 可更容易地在不同的数据类型间转换数据
  • 可使用 XML 编辑器来编辑 Schema 文件
  • 可使用 XML 解析器来解析 Schema 文件
  • 可以更容易地保护数据通信

如何自定义Schema?

(1)简单的做法可以直接基于 Spring的标准 Bean 来配置,但配置较为复杂或者需要更多丰富控制的时候,会显得非常笨拙。

(2)使用原生态的方式去解析定义好的 xml 文件,然后转化为配置对象,这种方式当然可以解决所有问题,但实现起来比较繁琐,特别是是在配置非常复杂的时候,解析工作是一个不得不考虑的负担。

(3)Spring 提供了可扩展 Schema 的支持,这是一个不错的折中方案,完成一个自定义配置一般需要以下步骤:


  1. 设计配置属性和 JavaBean
  2. 编写 XSD 文件
  3. 编写 NamespaceHandler 和 BeanDefinitionParser
  4. 编写 spring.handlers 和 spring.schemas 串联起所有部件
  5. 在 Bean 文件中应用

基于Spring的Schema扩展案例

(1)编写需要解析的bean:

public class ProviderParameter implements Serializable {
    private String interfaceName;
    private String host;
    private Integer port;
    public String getInterfaceName() {
        return interfaceName;
    }
    public void setInterfaceName(String interfaceName) {
        this.interfaceName = interfaceName;
    }
    public String getHost() {
        return host;
    }
    public void setHost(String host) {
        this.host = host;
    }
    public Integer getPort() {
        return port;
    }
    public void setPort(Integer port) {
        this.port = port;
    }
}

(2)编写XSD文件provider.xsd,并将文件放在META-INF下

<?xml version="1.0" encoding="UTF-8"?>  
<xsd:schema 
xmlns="http://syn.test.com/schema/provider" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:beans="http://www.springframework.org/schema/beans"
    targetNamespace="http://syn.test.com/schema/provider">
    <xsd:import namespace="http://www.springframework.org/schema/beans" />
    <xsd:element name="providerParameter">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="interfaceName" type="xsd:string" />
                    <xsd:attribute name="host" type="xsd:string" />
                    <xsd:attribute name="port" type="xsd:int" />
                 </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

(3)编写 NamespaceHandler 和 BeanDefinitionParser
NamespaceHandler:

public class ProviderNameSpaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        // TODO Auto-generated method stub
         registerBeanDefinitionParser("providerParameter", new ProviderBeanDefinitionParser());  
    }

}

BeanDefinitionParser:

public class ProviderBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    protected Class getBeanClass(Element element) {  
        return ProviderParameter.class;  
    }  
    protected void doParse(Element element, BeanDefinitionBuilder bean) {  
        String interfaceName = element.getAttribute("interfaceName");  
        String host = element.getAttribute("host");  
        String port = element.getAttribute("port");  
        if (StringUtils.hasText(port)) {  
            bean.addPropertyValue("port", Integer.parseInt(port));  
        }  
        if (StringUtils.hasText(interfaceName)) {  
            bean.addPropertyValue("interfaceName", interfaceName);  
        }  
        if (StringUtils.hasText(host)) {  
            bean.addPropertyValue("host", host);  
        }  
    } 
}

(4)编写 spring.handlers 和 spring.schemas 串联起所有部件,将这两个文件放在META-INF下

spring.handlers,用来解析XSD文件:

http://syn.test.com/schema/provider=basic.schema.ProviderNameSpaceHandler

spring.schemas:

http://syn.test.com/schema/provider/provider.xsd=META-INF/provider.xsd

(5)编写基于Spring的测试用例
Spring配置:
这里写图片描述

需要说明的是xml:provider用来指定自定义的schema,定义了这个下文中就可以使用< provider开头的标签。
用例编写:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
        "classpath:config/*.xml"
})
public class TestCase {

    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("config/spring-test.xml");  
        ProviderParameter p = (ProviderParameter)ctx.getBean("provider");  
        System.out.println("=====" + p);
    }
}

以上就是一个简单的基于Spring的Schema扩展。整体的流程可以跑通,但是因为还没有专门针对Schema学习过所以对于Schema中的一些配置的写法还有很多问题,先留下两个主要的记录下来:

(1)xmlns和targetnamespace的区别
(2)Spring按照什么样的规则寻找Schema,目前是把xmlns,targetnamespace,以及spring配置文件中使用同样的链接可以访问成功,如果后面需要变化应该如何处理?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值