spring xml扩展
??????? 从Spring 2.0版本开始支持扩展XML配置,开发人员可以扩展xml配置,根据bean的定义元素标签就能够看出改bean的作用,使组件的配置更加直观、易阅读。
扩展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()));
?}
}
运行测试类,将会按照配置文件中指定的格式打印输出当前时间。