Spring為自定義xml標(biāo)簽加載提供了擴(kuò)展伍派。用戶(hù)可自定義標(biāo)簽并注冊(cè)到Spring的bean容器中江耀。實(shí)現(xiàn)較為復(fù)雜的bean加載解析。
技術(shù)要點(diǎn):
- XML诉植、DTD祥国、XSD
什么是XML(EXtensible Markup Language)?
- XML 指可擴(kuò)展標(biāo)記語(yǔ)言(EXtensible Markup Language)
- XML 是一種標(biāo)記語(yǔ)言晾腔,很類(lèi)似 HTML
- XML 的設(shè)計(jì)宗旨是傳輸數(shù)據(jù)舌稀,而非顯示數(shù)據(jù)
- XML 標(biāo)簽沒(méi)有被預(yù)定義啊犬。您需要自行定義標(biāo)簽。
- XML 被設(shè)計(jì)為具有自我描述性壁查。
- XML 是 W3C 的推薦標(biāo)準(zhǔn)
什么是DTD(Document Type Definition)椒惨?
- 文檔類(lèi)型定義(DTD)可定義合法的XML文檔構(gòu)建模塊。它使用一系列合法的元素來(lái)定義文檔的結(jié)構(gòu)潮罪。DTD 可被成行地聲明于 XML 文檔中康谆,也可作為一個(gè)外部引用。
什么是XSD(XML Schema Definition)嫉到?
- XML Schema 的作用是定義 XML 文檔的合法構(gòu)建模塊沃暗,類(lèi)似 DTD。
XSD是DTD的繼任者
我們認(rèn)為 XML Schema 很快會(huì)在大部分網(wǎng)絡(luò)應(yīng)用程序中取代 DTD何恶。理由如下:
- XML Schema 可針對(duì)未來(lái)的需求進(jìn)行擴(kuò)展
- XML Schema 更完善孽锥,功能更強(qiáng)大
- XML Schema 基于 XML 編寫(xiě)
- XML Schema 支持?jǐn)?shù)據(jù)類(lèi)型
- XML Schema 支持命名空間
自定義Spring標(biāo)簽
自定義xsd:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://www.fpy.org/schema/beans/test"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.fpy.org/schema/beans/test"
elementFormDefault="qualified">
<xsd:element name="testBean">
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string" use="required" form="unqualified"/>
<xsd:attribute name="name" type="xsd:string" use="required" form="unqualified"/>
<xsd:attribute name="age" type="xsd:integer" use="required" form="unqualified"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
xmlns
:默認(rèn)命名空間,類(lèi)似import
targetNamespace
:定義文件內(nèi)標(biāo)簽所屬命名空間细层,類(lèi)似package
elementFormDefault
:在XML文檔中使用局部元素時(shí)惜辑,必須使用限定短名作為前綴
定義namespace與handler映射關(guān)系文件:
Spring解析xml文件時(shí),需要根據(jù)節(jié)點(diǎn)所在命名空間對(duì)應(yīng)的處理器來(lái)解析疫赎。Spring默認(rèn)從resources/META-INF/spring.handlers文件獲取映射關(guān)系盛撑。用戶(hù)也可自定義映射文件路徑。
spring.handlers
http\://www.fpy.org/schema/beans/test=com.example.demo.xsd.CustomNamespaceHandler
定義NamespaceHandler捧搞,解析自定義標(biāo)簽
繼承NamespaceHandlerSupport類(lèi)誉己,在init()方法中注冊(cè)自定義標(biāo)簽的解析器窖张,如testBean標(biāo)簽使用TestBeanDefinitionParser進(jìn)行解析。
TestBeanDefinitionParser實(shí)現(xiàn)BeanDefinitionParser接口,在parse()方法中添加自定義解析規(guī)則坪蚁,并注冊(cè)beanDefinition
public class CustomNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// 注冊(cè)標(biāo)簽parser
registerBeanDefinitionParser("testBean", new TestBeanDefinitionParser());
}
private static class TestBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition definition = new RootBeanDefinition();
definition.setBeanClass(TestBean.class);
MutablePropertyValues mpvs = new MutablePropertyValues();
mpvs.add("name", element.getAttribute("name"));
mpvs.add("age", element.getAttribute("age"));
definition.setPropertyValues(mpvs);
parserContext.getRegistry().registerBeanDefinition(element.getAttribute("id"), definition);
return null;
}
}
}
定義自定義標(biāo)簽xsd映射路徑
xml文件xsi:schemaLocation定義了命名空間對(duì)應(yīng)的xsd路徑晨缴,當(dāng)改路徑為http文檔時(shí)灸拍,避免因網(wǎng)絡(luò)問(wèn)題導(dǎo)致加載失敗崇堵,我們可在本地定義namespace和xsd的映射關(guān)系。Spring默認(rèn)從resources/META-INF/spring.schemas文件獲取映射關(guān)系爵憎。用戶(hù)也可自定義映射文件路徑慨亲。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:test="http://www.fpy.org/schema/beans/test"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.fpy.org/schema/beans/test http://www.fpy.org/schema/custom_namespace/CustomNamespaceHandlerTests.xsd"
default-lazy-init="true">
<test:testBean id="testBean" name="fengpingyu" age="28"/>
</beans>
將http://www.fpy.org/schema/custom_namespace/CustomNamespaceHandlerTests.xsd
映射到本地文件
spring.schemas
http\://www.fpy.org/schema/custom_namespace/CustomNamespaceHandlerTests.xsd=custom_namespace/CustomNamespaceHandlerTests.xsd
測(cè)試方法
public class CustomNsTests {
// namespace和handler映射關(guān)系文件
private static final String NS_PROPS = "custom_namespace/CustomNamespaceHandlerTests.properties";
// 測(cè)試xml文件
private static final String NS_XML = "custom_namespace/CustomNamespaceHandlerTests-context.xml";
// xml的xsd文件
private static final String TEST_XSD = "custom_namespace/CustomNamespaceHandlerTests.xsd";
@Test
public void testCustomNamespaceHandler() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
NamespaceHandlerResolver nhr = new DefaultNamespaceHandlerResolver(CustomNsTests.class.getClassLoader(), NS_PROPS);
XmlBeanDefinitionReader bd = new XmlBeanDefinitionReader(factory);
bd.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
// 自定義handlers文件路徑
bd.setNamespaceHandlerResolver(nhr);
// 自定義schemas文件路徑
bd.setEntityResolver(new DummySchemaResolver());
bd.loadBeanDefinitions(NS_XML);
TestBean testBean = (TestBean) factory.getBean("testBean");
System.out.println(JSONObject.toJSONString(testBean));
}
/**
* 自定義schemas路徑解析器
* 默認(rèn)從META-INF/spring.schemas文件讀取,讀取不到時(shí)就自定義路徑讀取
*/
private final class DummySchemaResolver extends PluggableSchemaResolver {
public DummySchemaResolver() {
super(CustomNsTests.class.getClassLoader());
}
@Override
public InputSource resolveEntity(String publicId, String systemId) throws IOException {
InputSource source = super.resolveEntity(publicId, systemId);
if (source == null) {
Resource resource = new ClassPathResource(TEST_XSD);
source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
}
return source;
}
}
}