http://docs.spring.io/spring/docs/current/spring-framework-reference/html/xml-custom.html
扩展spring 的 xml schema,如
<lzm:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm:ss"
lenient="true" />
使用时,需要在xml头部加入扩展的命名空间、该命名空间的别名(简称)、以及该命名空间对应的在线xsd地址。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:lzm="http://www.lzm.com/schema/lzm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans ;
http://www.springframework.org/schema/beans/spring-beans.xsd ;
http://www.lzm.com/schema/lzm http://www.lzm.com/schema/lzm/lzm.xsd">
<!-- as a top-level bean -->
<lzm:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm:ss"
lenient="true" />
<bean id="jobDetailTemplate" abstract="true">
<property name="dateFormat">
<!-- as an inner bean -->
<lzm:dateformat pattern="HH:mm MM-dd-yyyy" />
</property>
</bean>
</beans>
- xmlns:lzm=”http://www.lzm.com/schema/lzm”
表示声明一个命名空间,值是http://www.lzm.com/schema/lzm,它有一个别名(简称)lzm,用以在这个xml文件里代替该命名空间。 - http://www.lzm.com/schema/lzm http://www.lzm.com/schema/lzm/lzm.xsd
前面表示该命名空间,后面表示该命名空间对应的xsd(schema)的在线地址。
spring启动时,并不会立即使用该地址下载xsd,而是到META-INF/spring.schemas找该在线xsd地址对应的本地xsd位置。
http://www.lzm.com/schema/lzm/lzm.xsd=com/lzm/demo/extensible/xml/lzm.xsd
如果本地地址com/lzm/demo/extensible/xml/lzm.xsd找不到,才到使用这个http://www.lzm.com/schema/lzm/lzm.xsd地址去下载xsd。
3.<lzm:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm:ss" lenient="true" />
使用这个命名空间,lzm:dateformat,即命名空间的别名:element名称(在xsd里定义)。
扩展spring的xml schema,分以下几步:
1. 创建maven工程,引入spring 依赖。
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.lzm</groupId>
<artifactId>demo_extensible_xml</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<org.springframework.version>3.2.2.RELEASE</org.springframework.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
</dependencies>
<build>
<finalName>web</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.创建xsd(schema)文件。
lzm.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.lzm.com/schema/lzm"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://www.lzm.com/schema/lzm"
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>
定义了一个element,名称是dateformat。每个element都得有一个处理类(生成bean)。
3.创建命名空间处理类。
LzmNamespaceHandler.java
package com.lzm.demo.extensible.xml;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* @author 爱不留
* @date 2016年12月29日 上午10:56:38
* @Description: TODO
*/
public class LzmNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
}
}
将每个elelment及其对应的处理类都注册一下。
4.创建schema的element处理类(每个element对应1个处理类)。
SimpleDateFormatBeanDefinitionParser.java
package com.lzm.demo.extensible.xml;
import java.text.SimpleDateFormat;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* @author 爱不留
* @date 2016年12月29日 上午10:57:01
* @Description: TODO
*/
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.addConstructorArgValue(pattern);
// this however is an optional property
String lenient = element.getAttribute("lenient");
if (StringUtils.hasText(lenient)) {
bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
}
}
}
getBeanClass返回该element对应的bean的类型。
doParse设置该bean的构造参数或属性。该element的attribute可以用来当构造参数construct arg,也可以用于设置属性property value。
5.创建spring schema注册文件。
/META-INF/spring.handlers
http://www.lzm.com/schema/lzm=com.lzm.demo.extensible.xml.LzmNamespaceHandler
前面的表示命名空间,后面的表示命名空间处理类。
/META-INF/spring.schemas
http://www.lzm.com/schema/lzm/lzm.xsd=com/lzm/demo/extensible/xml/lzm.xsd
前面的表示命名空间对应的在线xsd地址(xsi:schemaLocation的后半部分),后面的表示本地xsd的位置。
6.使用命名空间
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:lzm="http://www.lzm.com/schema/lzm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans ;
http://www.springframework.org/schema/beans/spring-beans.xsd ;
http://www.lzm.com/schema/lzm http://www.lzm.com/schema/lzm/lzm.xsd">
<!-- as a top-level bean -->
<lzm:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm:ss"
lenient="true" />
<bean id="jobDetailTemplate" abstract="true">
<property name="dateFormat">
<!-- as an inner bean -->
<lzm:dateformat pattern="HH:mm MM-dd-yyyy" />
</property>
</bean>
</beans>
7.测试
ExtensiableXmlTest.java
package com.lzm.demo.extensible.xml;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author 爱不留
* @date 2016年12月29日 上午11:14:15
* @Description: TODO
*/
@Configuration
// @Import(ConfigA.class)
@ImportResource("classpath:/*.xml")
public class ExtensiableXmlTest {
public void init() {
System.out.println("init...");
}
public void cleanup() {
System.out.println("cleanup...");
}
@Bean(initMethod = "init", destroyMethod = "cleanup")
public ExtensiableXmlTest ex() {
return new ExtensiableXmlTest();
}
public static void main(String[] args) {
// ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/bean.xml");
ApplicationContext ctx = new AnnotationConfigApplicationContext(
ExtensiableXmlTest.class);
ExtensiableXmlTest ex = (ExtensiableXmlTest) ctx.getBean("ex");
SimpleDateFormat sdf = (SimpleDateFormat) ctx.getBean("defaultDateFormat");
String today = sdf.format(new Date());
System.out.println(today);
}
}
运行结果:
init...
2016-12-29 15:46:54
注意:
1. META-INF文件夹要在src/main/resources上右键,new一个folder(不是source folder)。
2.applicationContext.xml会识别不了新的命名空间,需要在eclipse里引入它的xsd。
Window - Preferences - XML - XML Catalog - User Specified Entries,Add 加入该xsd。
Location 是本地xsd位置,Key是在线xsd地址。
lzm.xsd会报错:src-resolve: Cannot resolve the name ‘beans:identifiedType’ to a(n) ‘type definition’ component.
不妨事,可以忽略。如果不想看到错误,可以取消schema的验证。
Window - Preferences - Validation - XML Schema Validator,把两个勾去掉。