曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中得到了什么(上)

曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享

曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解

曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,我们来试一下

曹工说Spring Boot源码(4)-- 我是怎么自定义ApplicationContext,从json文件读取bean definition的?

曹工说Spring Boot源码(5)-- 怎么从properties文件读取bean

曹工说Spring Boot源码(6)-- Spring怎么从xml文件里解析bean的

工程代码地址 思维导图地址

工程结构图:

曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中得到了什么(上)

概要

大家看到这个标题,不知道心里有答案了没?大家再想想,xml文件里都有什么呢?

这么一想,spring的xml文件里,内容真的很多,估计很多元素你也没配置过,尤其是这两年新出来的程序员,估计都在吐槽了,现在不都是注解了吗,谁还用xml?但其实,不管是xml,还是注解,都是配置信息,只是不同的表现形式而已,看过我前面几讲的同学,应该知道,我们用json、properties文件写过bean的配置信息。

所以,具体形式不重要,只是,xml和注解是最常用的两种表达方式罢了,我们这次就以xml为例来讲解。

xml中,其实还是很有条理的,各种元素,都按照namespace分得明明白白的,我列了个表格如下:

namespace element
util   constant、property-path、list、set、map、properties  
context   property-placeholder、property-override、annotation-config、component-scan、load-time-weaver、spring-configured、mbean-export、mbean-server  
beans   import、bean、alias  
task   annotation-driven、scheduler、scheduled-tasks、executor  
cache   advice、annotation-driven  
aop   config、scoped-proxy、aspectj-autoproxy  

大家看到了吗,spring其实对xml的支持才是最全面的,注解有的,xml基本都有。作为一个工作了6年的码农,我发现好多元素我都没配置过,更别说熟悉其内在原理了。但是呢,我们还是不能忘记了今天的标题,这么多元素,难道没有什么共性吗?spring解析这些元素,到底都是怎么实现的呢,且不说这些元素怎么生效,读了东西总需要地方存起来吧,那,是怎么存放的呢?

我们会挑选一些元素来讲解。我们本讲,先讲解spring采用的xml解析方式;再从util这个namespace开始,挑了constant这个元素进行深入讲解。

spring中所采用的xml解析方式

上一讲,我们讲了,spring是怎么解析xml元素的,我今天想办法从spring源码里,把它用来解析xml的主干代码提取了一下,基本就是下面这样的,比如针对如下xml文件,我们打算遍历一遍:

test-xml-read.xml: <?xml version="1.0" encoding="UTF-8"?> <f:table xmlns:f="http://www.w3school.com.cn/furniture" xmlns:t="http://www.w3school.com.cn/t"> <f:name>African Coffee Table</f:name> <f:width>80</f:width> <f:length>120</f:length> <t:abc></t:abc> </f:table>

那么,spring里的代码骨架,大概如下:

package org.springframework.bootstrap.sample; import lombok.extern.slf4j.Slf4j; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.io.InputStream; import java.net.URL; @Slf4j public class XmlSimpleUse { public static void main(String[] args) { //读取xml文件 URL url = Thread.currentThread().getContextClassLoader() .getResource("test-xml-read.xml"); InputStream inputStream = url.openStream(); //将流转变为InputSource,在后续xml解析使用 InputSource inputSource = new InputSource(inputStream); DocumentBuilderFactory factory = createDocumentBuilderFactory(); DocumentBuilder docBuilder = factory.newDocumentBuilder(); // 可选,设置实体解析器,其实就是:你可以自定义去哪里加载xsd/dtd文件 docBuilder.setEntityResolver(new EntityResolver() { @Override public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { return null; } }); // 设置回调处理器,当解析出现错误时,(比如xsd里指定了不能出现a元素,然后xml里出现了a元素) docBuilder.setErrorHandler(null); //解析xml文件,获取到Document,代表了整个文件 Document document = docBuilder.parse(inputSource); // 获取根元素 Element root = document.getDocumentElement(); log.info("root is {}",root); //获取根元素下的每个child元素 NodeList nodeList = root.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node instanceof Element) { Element ele = (Element) node; log.info("ele:{}",ele); } } } protected static DocumentBuilderFactory createDocumentBuilderFactory() { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); // Enforce namespace aware for XSD... factory.setNamespaceAware(true); return factory; } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfszg.html