• Spring可扩展的XML Schema机制


    可扩展的XML Schema机制

    从Spring2.0开始,Spring提供了XML Schema可扩展机制,用户可以自定义XML Schema文件,并自定义XML Bean解析器,并集成到Spring Ioc 容器中

    完成XML自定义扩展,需要下面几个步骤:

    • 创建一个 XML Schema 文件,描述自定义的合法构建模块,也就是xsd文件

    • 自定义个处理器类,并实现NamespaceHandler接口(比较容易)

    • 自定义一个或多个解析器,实现BeanDefinitionParser接口(最关键的部分)

    • 注册上面的组件到Spring IOC容器中

    按照上面的步骤,实现如下可扩展XML元素

    
      <myns:dateformat id="dateFormat" pattern="yyyy-MM-dd HH:mm" />
    
    

    可通过这种方式定义SimpleDateFormat

    类似

    
    <bean id="dateFormat" class="java.text.SimpleDateFormat"> 
    
        <constructor-arg value="yyyy-HH-dd HH:mm"/>
    
    </bean>
    
    

    1.自定义 XML Schema 文件

    XML Schema 介绍

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

    其中自定义的命名空间是http://www.lh.com/schema/myns,定义了dateformat元素,属性有pattern

    2.自定义 NamespaceHandler

    定义好XML Schema文件,需要定义一个NamespaceHandler解析配置文件。

    NamespaceHandler接口是非常简单的,只有三个方法:

    • init(): NamespaceHandler被使用之前调用,完成NamespaceHandler的初始化

    • BeanDefinition parse(Element, ParserContext): 当遇到顶层元素时被调用

    • BeanDefinition decorate(Node,BeanDefinitionHandler,ParserContext): 当遇到一个属性或者嵌套元素的时候调用

    Spring提供了一个默认的实现类NamespaceHandlerSupport,我们只需要在init的时候注册每个元素的解析器即可。

    
    public class DateformatNamespaceHandler extends NamespaceHandlerSupport { 
    
        public void init() { 
    
            registerBeanDefinitionParser("dateformat", new DeteformatDefinitionParser()); 
    
        }
    
    }
    
    

    这里实际用到了代理委托的概念,NamespaceHandlerSupport可以注册任意个BeanDefinitionParserNamespaceHandlerSupport负责所有自定义元素的编排,而解析XML的工作委托给各个BeanDefinitionParser负责。

    3.自定义BeanDefinitionParser

    BeanDefinitionParser 将被调用,如果NamespapceHandler遇到元素类型已经有对应注册的parser(例如上面的handler如果遇到dateformat,DateformatDefinitionParser会被调用,解析相应的属性设置到Bean中)将会被调用。BeanDefinitionParser负责解析一个顶级元素。

    Spring提供了AbstractSingleBeanDefinitionParser来处理繁重的解析工作,只需要实现两个方法:

    • Class<?> getBeanClass(Element):返回元素的Class类型

    • void doParse(Element element,BeanDefinitionBuilder builder):添加元素的属性或者构造参数等等

    
    package com.lh.spring;
    
    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
    
    import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
    
    import org.w3c.dom.Element;import java.text.SimpleDateFormat;
    
    public class DateformatDefinitionParser extends AbstractSingleBeanDefinitionParser { 
    
        @Override 
    
        protected Class<?> getBeanClass(Element element) { 
    
            return SimpleDateFormat.class; 
    
        } 
    
        @Override
    
        protected void doParse(Element element, BeanDefinitionBuilder builder) { 
    
            String pattern = element.getAttribute("pattern"); 
    
            builder.addConstructorArgValue(pattern); 
    
        }
    
    }
    
    

    4.注册handler和schema

    为了让Spring在解析xml的时候能够感知到我们的自定义元素,我们需要把namespaceHandler和xsd文件放到2个指定的配置文件中,这2个文件都位于META-INF目录中

    4.1spring.handlers文件包含了xml schema uri 和 Handler类的映射关系,例如

    
    http\://www.lh.com/schema/myns=com.lh.spring.DateformatNamespaceHandler
    
    

    遇到http://www.lh.com/schema/myns名空间的时候会交给CarNamespaceHandler来处理,key部分必须和xsd文件中的targetNamespace值保持一致

    4.2 spring.schemas文件包含了xml schema xsd文件命名空间和文件路径的映射关系,例如

    
    http\://www.lh.com/schema/myns.xsd=META-INF/com.lh.date.format/sfm-1.0.xsd
    
    

    5.实践测试

    5.1 加入Spring配置文件:

    
    <?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:my="http://www.lh.com/schema/myns" 
    
               xsi:schemaLocation=" http://www.springframework.org/schema/beans
    
                                    http://www.springframework.org/schema/beans/spring-beans.xsd
    
                                    http://www.lh.com/schema/myns 
    
                                    http://www.lh.com/schema/myns.xsd"> 
    
        <my:dateformat id="dateformat" pattern="yyyy-MM-dd HH:mm" />
    
    </beans>
    
    

    5.2 单元测试:

    全部代码

    
    package com.lh.spring;
    
    import org.junit.Assert;
    
    import org.junit.Test;
    
    import org.junit.runner.RunWith;
    
    import org.springframework.beans.factory.annotation.Autowired;
    
    import org.springframework.test.context.ContextConfiguration;
    
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import java.text.ParseException;
    
    import java.text.SimpleDateFormat;
    
    import java.util.Date;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    
    @ContextConfiguration(locations = {"classpath:spring/application-core.xml"})
    
    public class XMLSchemaCustomTest { 
    
        @Autowired private SimpleDateFormat dateFormat;
    
        @Test 
    
        public void propertyTest() { 
    
            Assert.assertNotNull(dateFormat);
    
            String date = "2010-10-10 11:12:14";
    
            SimpleDateFormat ymdhms = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
    
            try { 
    
                Date time = ymdhms.parse(date); 
    
                String dateFormatStr = dateFormat.format(time); 
    
                Assert.assertTrue("2010-10-10 11:12".equals(dateFormatStr));
    
            } catch (ParseException e) { 
    
                e.printStackTrace(); 
    
            } 
    
        }
    
    }
    
    
  • 相关阅读:
    Kubernetes使用Keda进行弹性伸缩,更合理利用资源
    Kubernetes Pod中容器的Liveness、Readiness和Startup探针
    DSSM在召回和粗排的应用举例
    计算广告笔记
    500行SQL快速实现UCF
    Reflect的详解及用法
    Proxy 代理的使用和介绍
    2020年年度总结
    (六)小程序封装原生请求
    (五)小程序的页面跳转--自定义组件--及相关使用)
  • 原文地址:https://www.cnblogs.com/beginmind/p/5990005.html
Copyright © 2020-2023  润新知