在spring2.0之后支持xml schema的方式扩展xml的配置。这样对于一些常用的属性较多的bean的配置,可以采用这种方式进行简化
要使用这种方式,只需要做以下几件事情:
1.定义xml schema文件(.xsd格式)
2.实现NamespaceHandler接口,将Xml Element元素转换为BeanDefinition,并注册到BeanDefinitionRegistry中。
3.指定namespace到xsd的文件映射关系的文件spring.schemas,放到classpath根目录下的META-INF文件夹中。该文件主要是用于spring对配置文件进行validate以及元素默认值的指定。
4.指定namespace到NamespaceHandler的映射关系文件spring.handlers,同样放到classpath根目录下的META-INF文件夹中。
这里有两个需要指出的地方。
首先,这里的StudentNamespaceHandler是继承NamespaceHandlerSupport,而不是实现NamespaceHandler,这里NamespaceHandlerSupport帮我们做了一部分的解析逻辑,我们只需要关注每个element怎么处理就行了,这样免去自己做一些重复的工作。
其次,NamespaceHandler并没有把如何将一个xml Element转换成BeanDefinition这段逻辑实现,而是把工作交给了专业处理类BeanDefinitionParser。这样结构更清晰。所以我们这里需要实现StudentBeanDefinitionParser。
要使用这种方式,只需要做以下几件事情:
1.定义xml schema文件(.xsd格式)
2.实现NamespaceHandler接口,将Xml Element元素转换为BeanDefinition,并注册到BeanDefinitionRegistry中。
3.指定namespace到xsd的文件映射关系的文件spring.schemas,放到classpath根目录下的META-INF文件夹中。该文件主要是用于spring对配置文件进行validate以及元素默认值的指定。
4.指定namespace到NamespaceHandler的映射关系文件spring.handlers,同样放到classpath根目录下的META-INF文件夹中。
5.在spring配置文件通过namespace引入定义的.xsd文件后,就可以使用啦。
下面通过一个具体例子来说明具体的使用方法:
1.定义xml schema文件
为了便于说明,先定义一个简单的对象:
package com.alibaba.china.pojo;
public class Student {
private String name;
private int age;
private String school;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
根据这个对象定义xml schema文件:student.xsd,放到com/alibaba/china/pojo/目录下
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.alibaba.org/schema/student"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://www.alibaba.org/schema/student"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:element name="student">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="age" type="xsd:int" default="100"/>
<xsd:attribute name="name" type="xsd:string"/>
<xsd:attribute name="school" type="xsd:string"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<xsd:extension base="beans:identifiedType"> 中beans:identifiedType是在spring自带的xsd中定义,用于为每个bean添加id,以保证bean的唯一性。
2. 实现NamespaceHandler接口
com.alibaba.china.study.tf.handler;
public class StudentNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
// TODO Auto-generated method stub
this.registerBeanDefinitionParser("student", new StudentBeanDefinitionParser());
}
}
上面这段代码的说明,当元素为student时,采用StudentBeanDefinitionParser进行解析
这里有两个需要指出的地方。
首先,这里的StudentNamespaceHandler是继承NamespaceHandlerSupport,而不是实现NamespaceHandler,这里NamespaceHandlerSupport帮我们做了一部分的解析逻辑,我们只需要关注每个element怎么处理就行了,这样免去自己做一些重复的工作。
其次,NamespaceHandler并没有把如何将一个xml Element转换成BeanDefinition这段逻辑实现,而是把工作交给了专业处理类BeanDefinitionParser。这样结构更清晰。所以我们这里需要实现StudentBeanDefinitionParser。
public class StudentBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition bd = new RootBeanDefinition();
bd.setBeanClass(Student.class);
//注册beanDefinition到BeanDefinitionRegistry中
String beanName = element.getAttribute("id");
BeanDefinitionHolder holder = new BeanDefinitionHolder(bd, beanName);
BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());
bd.getPropertyValues().addPropertyValue("age", element.getAttribute("age"));
bd.getPropertyValues().addPropertyValue("school", element.getAttribute("school"));
bd.getPropertyValues().addPropertyValue("name", element.getAttribute("name"));
return bd;
}
}
3.定义spring.schemas配置文件
指出http://www.alibaba.org/schema/student.xsd文件对应的本地路径是com/alibaba/china/pojo/student.xsd
http\://www.alibaba.org/schema/student.xsd=com/alibaba/china/pojo/student.xsd
4. 定义spring.handlers配置文件
指出http://www.alibaba.org/schema/student命名空间下的元素采用com.alibaba.china.study.tf.handler.StudentNamespaceHandler类进行处理。http\://www.alibaba.org/schema/student=com.alibaba.china.study.tf.handler.StudentNamespaceHandler
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:tag="http://www.alibaba.org/schema/student"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.alibaba.org/schema/student
http://www.alibaba.org/schema/student.xsd">
<tag:student id="student" name="jianchi" school="NJUST" age="26"></tag:student>
</beans>
5.2 调用代码
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Student st = (Student) context.getBean("student");
System.out.println(st.getName() + " age:" + st.getAge());
}
}
5.3输出
tanfeng age:26