基于Spring的Schema扩展

基于Spring的Schema扩展

阅读Spring源码中,发现Spring提供了可扩展Schema的支持,让我想到了其他的框架中的自定义标签是否也是使用了这个。比如,dubbo中的一些可扩展Schema的支持。在翻阅源码后,发现dubbo也是使用了Spring提供的Schema的支持。根据Spring的介绍,分为如下几个步骤:

  • 设计配置写对应的Bean
  • 编写XSD文件
  • 编写NamespaceHandler和BeanDefinitionParser完成解析工作
  • 编写spring.handlers和spring.schemas串联起所有部件
    下面介绍一个例子来带入

首先我们要想要设计一个Sasukeer的扩展比如是

<myName:sasukeer blogUrl="www.baidu.com" name="Sasukeer" age="23"/>

那么首先需要一个对应的javaBean如下:

public class Sasukeer {
	private String blogUrl;
    private String name;
    private String age;
}

下一步需要编写xsd文件来,来最为一个编写和解析的规则:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
        xmlns="http://github.com/wkztselina/sasukeer"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:beans="http://www.springframework.org/schema/beans"
        elementFormDefault="qualified"
        targetNamespace="http://github.com/wkztselina/sasukeer"
        attributeFormDefault="unqualified">
    <xsd:import namespace="http://www.springframework.org/schema/beans" />
    <xsd:element name="sasukeer">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="name" type="xsd:string" />
                    <xsd:attribute name="age" type="xsd:string" />
                    <xsd:attribute name="blogUrl" type="xsd:string" />
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

一般把XSD文件,放在META-INF的目录下面,这个目录一般都是放置用来配置应用程序、扩展程序、类加载器和服务的文件。就好像dubbo中使用了java的spi机制,就把具体实现类的信息放在改目录下面,方便为某个接口寻找实现类,也方便修改实现类。同样,关于xsd:schema具体含义就不作过多解释,参见http://www.w3school.com.cn/schema/schema_schema.asp

下一步编写对应的解析类

public class MyBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    @Override
    protected Class<?> getBeanClass(Element element) {
        return Sasukeer.class;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String name = element.getAttribute("name");
        String age = element.getAttribute("age");
        String blogUrl = element.getAttribute("blogUrl");
        if (StringUtils.hasText(blogUrl)) {
            builder.addPropertyValue("blogUrl", blogUrl);
        }
        if (StringUtils.hasText(name)) {
            builder.addPropertyValue("name", name);
        }
        if (StringUtils.hasText(age)) {
            builder.addPropertyValue("age", age);
        }
    }
}
public class MyNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        registerBeanDefinitionParser("sasukeer",new MyBeanDefinitionParser());
    }
}

通过继承NamespaceHandlerSupport,可以让我们指定sasukeer的解析器。然后由我们指定的解析器来解析,同时解析器继承AbstractSingleBeanDefinitionParser可以简化操作一部分解析的操作。
当完成上面的操作之后,我们需要的组件已经完成,只需要把他们之间关联起来就可以了。所以,需要编写spring.handlers和spring.schemas串联起所有部件。本例中的spring.handlers如下:

http\://github.com/wkztselina/sasukeer= wkzt.test.xsd.MyNamespaceHandler

所以当使用到名为"http://github.com/wkztselina/sasukeer"的引用的时候,就会调用MyNamespaceHandler来进行解析

spring.schemas如下

http\://github.com/wkztselina/sasukeer.xsd=META-INF/sasukeer.xsd

spring.schemas和spring.handlers都需要在META-INF目录下面

测试一下:如下
先写配置文件:

<?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:myName="http://github.com/wkztselina/sasukeer"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://github.com/wkztselina/sasukeer  http://github.com/wkztselina/sasukeer.xsd">
    <myName:sasukeer id="test" blogUrl="www.baidu.com" name="Sasukeer" age="23"/>

</beans>
public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
        Sasukeer p = (Sasukeer)ctx.getBean("test");
        System.out.println(p.getBlogUrl());
        System.out.println(p.getName());
        System.out.println(p.getAge());
    }

就可以加载到想要的结果。

www.baidu.com
Sasukeer
23

在mvn的项目中,可以再resources中创建META-INF目录,网上有遇到过mvn项目构建时覆盖了自己的META-INF目录,可以用如下代码:

<build>
        <plugins>
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <classesDirectory>target/classes/</classesDirectory>
                    <archive>
                        <addMavenDescriptor>false</addMavenDescriptor>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

在了解Spring的扩展以后,查看一下dubbo的源码,是否也是这样在使用如下:

public class DubboNamespaceHandler extends NamespaceHandlerSupport {

    static {
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }

    @Override
    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }

}

可以看到service、reference、consumer等都在。由于dubbo所支持的标签不多,所以都对其做了DubboBeanDefinitionParser的解析。由此可以得到,dubbo也是使用了Spring的扩展。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值