首先按照正常的逻辑去解析一个 XML 配置文件;
/**
* 测试解析XML配置文件
*/
public class ParseXMLTest {
@Test
public void parse() {
try {
// 1、获取XML资源
InputStream in = new InputStreamResource(getClass().getResourceAsStream("test.xml")).getInputStream();
// 2、获取DocumentBuilderFactory实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 3、获取DocumentBuilder实例
DocumentBuilder docBuilder = factory.newDocumentBuilder();
// 4、将docBuilder转换为Document
Document doc = docBuilder.parse(in);
// 5、获取节点并循环输出节点值
Element element = doc.getDocumentElement();
NodeList childNodes = element.getChildNodes();
// 解析,测试拿一些数据
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
NamedNodeMap attributesMap = node.getAttributes();
if (null != attributesMap) {
System.out.println(attributesMap.getNamedItem("id"));
System.out.println(attributesMap.getNamedItem("class"));
}
}
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
}
例如一个配置文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="validEmptyWithDescription" class="org.springframework.beans.testfixture.beans.TestBean">
<description>
I have no properties and I'm happy without them.
</description>
</bean>
<bean id="aliased" class=" org.springframework.beans.testfixture.beans.TestBean " name="myalias">
<property name="name">
<value>aliased</value>
</property>
</bean>
<alias name="aliased" alias="youralias"/>
<alias name="multiAliased" alias="alias3"/>
<bean id="multiAliased" class="org.springframework.beans.testfixture.beans.TestBean" name="alias1,alias2">
<property name="name">
<value>aliased</value>
</property>
</bean>
</beans>
接下来看一下 Spring 是如何处理这个解析的:
从这开始:XmlBeanDefinitionReader#doLoadDocument
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
再进入 DefaultDocumentLoader#loadDocument 可以看出利用方法 createDocumentBuilderFactory 得到解析工厂;
然后利用 createDocumentBuilder 方法得到解析器;
这两个方法和我们上面的测试代码几乎是一样的,只不过是多了一些校验和回调方法;
@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
最终 builder.parse(inputSource);
解析 XML 得到 Document;