扩展XML配置大致需要一下几个步骤
1、定义一个xsd文件描述组件内容
2、创建一个bean 定义解析器,实现BeanDefinitionParser接口,用来解析xsd文件中描述的元素。
3、创建一个名称空间解析器,实现NamespaceHandler接口,一般都是扩展NamespaceHandlerSupport类,作用是将组件注册到Spring容器
4、编写spring.handlers和spring.schemas文件,即注册处理器和方案。
首先编写xsd文件:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.org/schema/myns"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://www.springframework.org/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>
上面的xsd文件描述了一个新的targetNamespace,并在这个空间中定义了一个name为dateformat的element,改元素有两个属性lenient和pattern。
编写bean定义解析器,实现了BeanDefinitionParser接口,用来解析xsd文件中定义的元素并注册到spring 容器中。
package com.springinaction.xmlextension;
import java.text.SimpleDateFormat;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
public class SimpleDateFormatBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition beanDef = new RootBeanDefinition();
beanDef.setBeanClass(SimpleDateFormat.class);
String pattern = element.getAttribute("pattern");
beanDef.getConstructorArgumentValues().addGenericArgumentValue(pattern);
//这是因为pattern属性是构造函数中的一个参数,所以需要调用
//getConstructorArgumentValues()方法,而不是和lenient属性一样处理
String lenientString = element.getAttribute("lenient");
if (StringUtils.hasText(lenientString)) {
beanDef.getPropertyValues().addPropertyValue("lenient", new Boolean(lenientString));
}
String id = element.getAttribute("id");
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDef, id);
//注册bean定义到spring 容器中,此处也可不注册,spring 容器会帮助我们自//动注册
BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());
return beanDef;
}
}
注意,id属性是一个默认的属性,可以不在xsd文件中描述,但是需要注册它,否则将无法通过getBean方法获取标签定义的bean,也无法被其他bean引用。
编写名称空间解析器,扩展自NamespaceHandlerSupport,它的作用是将组件注册到Spring容器,我们一般只需要在它的init()方法中注册bean定义解析器,不需要做其它的。
package com.springinaction.xmlextension;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class MyNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("dateformat",
new SimpleDateFormatBeanDefinitionParser());
}
}
编写spring.handlers:
http\://www.springframework.org/schema/myns=com.springinaction.xmlextension.MyNamespaceHandler
编写spring.schemas:
http\://www.springframework.org/schema/myns/myns.xsd=com/springinaction/xmlextension/myns.xsd
spring.schemas将告诉Spring 扩展的xsd文件存放在什么位置。
而spring.handlers文件将告诉Spring,schema和handler的映射关系,某个schema应该有哪个handler来处理。
配置文件和测试类:
<?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.springframework.org/schema/myns"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/myns http://www.springframework.org/schema/myns/myns.xsd">
<myns:dateformat id="dateFormat"
pattern="yyyy-MM-dd HH:mm"
lenient="true"/>
</beans>
package com.springinaction.xmlextension;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class Test {
public static void main(String[] args) {
BeanFactory bf = new XmlBeanFactory(
new ClassPathResource("com/springinaction/xmlextension/extension.xml"));
SimpleDateFormat sdf = (SimpleDateFormat)bf.getBean("dateFormat");
System.out.println(sdf.format(new Date()));
}
}
运行测试类,将会按照配置文件中指定的格式打印输出当前时间。