原文地址:www.jianshu.com/p/8639e5e9f…php
從Spring 2.0版本開始,Spring提供了XML Schema可擴展機制,用於定義和配置Bean。完成XML自定義擴展,須要下面幾個步驟:java
NamespaceHandler
接口。BeanDefinitionParser
接口(最關鍵的部分)。按照上面的步驟,實現以下可擴展XML元素:spring
<myns:dateformat id="dateFormat" pattern="yyyy-MM-dd HH:mm" lenient="true"/>
複製代碼
等價於dom
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-HH-dd HH:mm"/>
<property name="lenient" value="true"/>
</bean>
複製代碼
<!-- myns.xsd (inside package org/springframework/samples/xml) -->
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.mycompany.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>
複製代碼
NamespacespaceHandler
用於解析配置文件時遇到的特定命名空間的全部元素。在咱們的例子中,NamespaceHandler
應該處理myns:dateformat
元素的解析。ide
NamespaceHandler
提供以下三個方法:ui
init()
: NamespaceHandler被使用以前調用,完成NamespaceHandler的初始化。BeanDefinition parse(Element, ParserContext)
: 當遇到頂層元素時被調用。BeanDefinition decorate(Node,BeanDefinitionHandler,ParserContext)
: 當遇到一個屬性或者嵌套元素的時候調用。Spring提供了一個默認的實現類NamespaceHandlerSupport
,咱們只須要在init的時候註冊每一個元素的解析器便可。this
public class DateformatNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("dateformat", new DeteformatDefinitionParser());
}
}
複製代碼
這裏實際用到了代理委託的概念,NamespaceHandlerSupport
能夠註冊任意個BeanDefinitionParser
。NamespaceHandlerSupport
負責全部自定義元素的編排,而解析XML的工做委託給各個BeanDefinitionParser
負責。spa
若是NamespapceHandler
遇到元素類型(如:dateformat
)已經有對應註冊的parser,則DateformatDefinitionParser
會被調用,解析相應的屬性設置到Bean中。BeanDefinitionParser負責解析一個頂級元素。代理
Spring提供了AbstractSingleBeanDefinitionParser
來處理繁重的解析工做,只須要實現兩個方法:code
Class<?> getBeanClass(Element)
:返回元素的Class類型。void doParse(Element element,BeanDefinitionBuilder builder)
:添加元素的屬性或者構造參數等等。ppackage org.springframework.samples.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));
}
}
}
複製代碼
爲了讓Spring在解析xml的時候可以感知到咱們的自定義元素,咱們須要把NamespaceHandler
和xsd文件
放到2個指定的配置文件中,這2個文件都位於META-INF
目錄中
'META-INF/spring.handlers'
:包含XML Schema URI到命名空間處理程序類的映射。所以,對於咱們的示例,咱們須要編寫如下內容:
http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.DateformatNamespaceHandler
複製代碼
META-INF/spring.schemas
:包含XML Schema xsd到類路徑資源的映射。
http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd
複製代碼
<?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.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd">
<!-- as a top-level bean -->
<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>
複製代碼