转载

Spring自定义标签

0x01、说明

Spring中支持标签级的扩展,例如用到的dubbo和axis2,都可以看到在Spring配置文件中配置各自框架的自定义标签。今天咱们就来尝试自己配置一个自定义标签。

配置自定义标签的过程有以下四个步骤

  • Authoring an XML schema to describe your custom element(s). 创建XML的XSD来描述您的自定义元素。
  • Coding a custom NamespaceHandler implementation (this is an easy step, don’t worry). 创建一个NamespaceHandler的子类
  • Coding one or more BeanDefinitionParser implementations (this is where the real work is done). 写BeanDefinitionParser的实现(这是一个很重要的步骤)
  • Registering the above artifacts with Spring (this too is an easy step).注册上述的handler和schema

下面来安装上述步骤来自定义Spring标签。

以下面的日期格式化为例,咱要自顶一个一个日期格式化的标签,并且可以指定日期的格式。

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

0x02、写一个XML Schema 文件

在com/jialeens/xml目录下创建一个xml文件,命名为myns.xsd。

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.jialeens.com/schema/myns" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://www.mycompany.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="lenient" type="xsd:boolean"/>
                    <xsd:attribute name="pattern" type="xsd:string" use="required"/>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

0x03、编写NamespaceHandler

现在咱们实现一个NamespaceHandler的子类,他的作用是去注册标签和对应的xml解析的类

package com.jialeens.xml;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class MyNamespaceHandler extends NamespaceHandlerSupport {

    public void init() {
        registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
    }

}

0x04、实现BeanDefinitionParser

BeanDefinitionParser的作用是去解析Spring中配置的xml配置信息,他负责去解析标签中的属性和配置信息。同时,负责去构建自己要定义的bean。

package com.jialeens.xml;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

import java.text.SimpleDateFormat;

public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 

    protected Class getBeanClass(Element element) {
        return SimpleDateFormat.class; 
    }

    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        // this will never be null since the schema explicitly requires that a value be supplied
        String pattern = element.getAttribute("pattern");
        bean.addConstructorArg(pattern);

        // this however is an optional property
        String lenient = element.getAttribute("lenient");
        if (StringUtils.hasText(lenient)) {
            bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
        }
    }
}

0x05、注册handler和schema

实现了上述的schema和handler与parser,现在需要在Spring中实现注册功能,

在META-INF下面创建两个文件spring.handlers和spring.schemas,内容如下:

spring.handlers:

http/://www.jialeens.com/schema/myns=com.jialeens.xml.MyNamespaceHandler

spring.schemas:

http/://www.jialeens.com/schema/myns.xsd=myns.xsd

上面的作用分别将namespace和handler进行了绑定,同时也将xsd与真正的文件进行了绑定

0x06、测试

进行了上述的配置之后,就可以进行测试了

首先创建一个简单的Spring配置文件,myns.xml

<?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:myns="http://www.mycompany.com/schema/myns"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.jialeens.com/schema/myns http://www.jialeens.com/schema/myns.xsd">


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

    <bean id="jobDetailTemplate" abstract="true">
        <property name="dateFormat">
            <!-- as an inner bean -->
            <myns:dateformat pattern="HH:mm MM-dd-yyyy"/>
        </property>
    </bean>
</beans>

然后再写一个测试类

package com.jialeens.xml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import java.text.SimpleDateFormat;
import java.util.Date;</span>
<span style="font-family: 'comic sans ms', sans-serif;">
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("myns.xml");
        SimpleDateFormat info = (SimpleDateFormat) context.getBean("dateFormat");
        System.out.println(info.format(new Date()));
    }
}

运行后,可以看到控制台输出了当前的时间

0x07、总结

XML通常通过DTD、XSD定义,但DTD的表达能力较弱,XSD定义则能力比较强,能够定义类型,出现次数等。自定义标签需要XSD支持,在实现时使用Namespace扩展来支持自定义标签。

从上面的示例可以看到,对于每一个标签,都可以认为他等同于一个bean,例如上面xml中的jobDetailTemplate,只不过使用标签可以使xml中的定义更个性化,同时也更容易辨识出其具体的作用。

相关资料

http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#xml-custom

原文  http://www.jialeens.com/archives/562
正文到此结束
Loading...