接sping源码分析(二)
doLoadBeanDefinitions去解析 inputResoucre 和Resource 的具体实现:
这里解析 成Document 的操作主要是运用了 JDK自带的XML解析工具JAXP。同时还涉及 profile 以及 XML验证 DTD、XSD 的验证方法。
解析成document的操作:
这里 使用DocumentLoader 接口 来解析配置文件的 这里使用的是它的默认实现DefaultDocumentLoader同时也涉及EntityResolver
DefalutDocumentLoader 解析document 的进一步操作:
这里是获取DocumentBuilderFactory
这里 使用了 XSD 的验证格式验证
这里是DocumentBuilder的生成:
这里普及一下JAXP的一些基本的知识:
Java API for XML(JAXP)
作用:解析XML文档的一套Java API,其为DOM和SAX两种解析机制提供了支持。
缺陷:使用繁琐,代码量大,可读性低。
解决方法:使用dom4j或JDOM解析器。
JAXP本身没有提供任何的XML解析支持,所以JAXP依赖与XML解析器,但其本身不与任何XML解析器耦合,因此可轻松在各种XML解析器直接切换而无须修改源代码,本质解释XML解析器与应用程序直接的抽象层。
JAXP由JDK直接提供,其包括:
javax.xml包及其子包;
org.w3c.dom包及其子包;
org.xml.sax包及其子包。
DOM:Document Object Model,W3C推荐使用。
特点:一次性将整份XML导入内存,转换成DOM树,因此转换速度慢;但因为常驻内存,所以重复访问效率高,并且可修改节点内容。
SAX:Simple API for XML,费W3C推荐标准,但确实XML行业规范。
特点:顺序解析,无需一次性导入,转换速度快;不保持以访问过的数据,所以重复访问效率低(需要重新解析XML),且无法修改节点内容。
解析器:目前最流行的是Apache组织的Xerces项目。 网址:http://xerces.apache.org/
xerces提供的包
xml-apis.jar:该包就是DOM和SAX标准的核心包,该包里几乎全是接口。
xercesImpl.jar:核心类库。
下面简单介绍下java.xml.parsers包
DocumentBuilderFactory:获取DOM解析器的工厂;
DocumentBuilder:用于从XML文档中获取DOM文档实例;
SAXParserFactory:获取SAX解析器的工厂;
SAXParser:包装一个SAX解析器。
DocumentBuilder、SAXParser都是抽象类,其实现由XML解析器完成。
jdk1.4默认包括一种解析器Crimson,jdk1.5 左右XML解析器默认是Apache组织的Xerces。 可以通过JVM或者工厂方法参数的配置来改变jaxp的解析器。
简单代码示例DocumentBuilderFactory的用法:
public class XmlParserTest {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder
.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("char02/test.xml"));
Element root = doc.getDocumentElement();
NodeList books = root.getChildNodes();
if (books != null) {
for (int i = 0; i < books.getLength(); i++) {
Node book = books.item(i);
if(book.getNodeType()==Node.ELEMENT_NODE){
String email=book.getAttributes().getNamedItem("id").getNodeValue();
System.out.println("email:"+email);
for (Node node = book.getFirstChild(); node != null; node = node.getNextSibling()) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
if(node.getNodeName().equals("name")){
System.out.println(node.getTextContent());
System.out.println("name:"+node.getFirstChild().getNodeValue());
}
if(node.getNodeName().equals("price")){
System.out.println("price:"+node.getFirstChild().getNodeValue());
}
}
}
}
}
}
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<books>
<book id="01">
<name>testname</name>
<price>10.00</price>
</book>
<book id="02">
<name>testname02</name>
<price>10.02</price>
</book>
</books>
继续源码分析:
获取到Document要去注册 BeanDefinitionDocument
这里又 交给我了DocumentReader去注册:
BeanDefinitionDocumentReader 是一个接口,只有一个默认的实现DefaultBeanDefinitionDocumentReader
注册代码为:
处理Elemet:
这里的解析之前的操作和解析之后的操作 都是空的 可以自定义操作:
解析 操作:
红色标记表示对bean的操作:
- spring 中有两大bean声明:
- 一类是默认的:
- 另一类是:
tx:annotation-driven/
注册代码:
2017/5/13 查看源码的时候发现
这里的 beanDefinitionDocumentReader 既然是 通过反射生成的,查看代码知道 beanDefinitionDocumentReader 是可以配置的 但是必须实现beanDefinitionDocumentReader 接口。