上一节,我们知道Spring对xml文件的校验有两种方式,分别是DTD和XSD。这两种校验方式都有对应的解析器来获取jar包中的声明文件的。

Spring如何获取url spring如何获取dn_xml文件

获取dtd的声明文件

我们先到BeansDtdResolver这个类,看下dtd的声明文件是如何获取

Spring如何获取url spring如何获取dn_Spring如何获取url_02


进入到BeansDtdResolver类中,就发现了一个resolverEntity的方法,很明显它就是解析并获取dtd文件的方法,调用该方法传入了两个参数publicId、systemId。

Spring在解析XML文件时,会从xml文件中获取到这两个参数的值,分别如下:

publicId:-//SPRING//DTD BEAN//EN

systemId:http://www.springframework.org/dtd/spring-beans.dtd不知道大家有没有发现,在创建ClassPathResource时候,传入了getClass()方法,该方法表示传入了当前类,也就是BeansDtdResolver,这样的话ClassPathResource就会从classpath找BeansDtdResolver类相同包名的路径,寻找相应的spring-beans.dtd文件。

Spring如何获取url spring如何获取dn_后端_03

获取XSD声明文件

我们再到PluggableSchemaResolver类中,看下如何获取xsd的声明文件。

Spring如何获取url spring如何获取dn_spring_04


可以看到,在PluggableSchemaResolver 类中也有相同的resolveEntity方法,而且同样需要传入参数publicId和systemId。

Spring如何获取url spring如何获取dn_Spring如何获取url_05


publicId: null

systemId: http://www.springframework.org/schema/beans/spring-beans.xsd

通过对比发现,publicId这个参数的校验值只有DTD类型才有,参数systemId就是声明文件的下载地址。在PluggableSchemaResolver 类中的resolveEntity方法是通过调用getSchemaMappings() 方法之后,然后传入参数systemId,来获取资源路径。那这个getSchemaMappings()方法又有什么作用呢?我们跟进去看一下

Spring如何获取url spring如何获取dn_后端_06


在getSchemaMappings方法中,成员变量schemaMappings一开始为空。接下来是通过PropertiesLoaderUtils的loadAllProperties的方法,传入了两个参数 schemaMappingsLocation 、classloader。那这个schemaMappingsLocation 又是什么呢?如下图:

Spring如何获取url spring如何获取dn_spring_07


在PluggableSchemaResolver类的构造方法中,会给成员变量schemaMappingsLocation 赋值为META-INF/spring.schemas。也就是说PropertiesLoaderUtils的loadAllProperties就是加载spring.schemas文件中所有的值。那具体加载的是什么值呢?,我们到spring-beans项目中的META-INF目录中看一下:

Spring如何获取url spring如何获取dn_后端_08


看到这里我们算是明白了,原来spring.schemas文件中,存放的就是以systemId为key,XSD声明文件在项目中的包路径为value,所以我们可以通过systemId: http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

获取到value值:org/springframework/beans/factory/xml/spring-beans.xsd。

原来相比于DTD声明文件的获取方式,XSD声明文件的获取,还要根据具体的配置配置来寻找。

Spring如何获取url spring如何获取dn_java_09


这个方法,会把spring.schemas中所有的值封装成一个Map然后返回,接下来我们可以通过参数systemId的值,获取xsd文件在项目中的路径,然后就可以获取到xsd声明文件了。

Spring如何获取url spring如何获取dn_java_10


通过systemId从schemaMappings中获取resourceLocation,就是我们org/springframework/beans/factory/xml/spring-beans.xsd的值。也就是spring-beans.xsd声明文件在项目中的位置。接下来可以通过ClasspathResource,到classpath路径的resourceLocation位置加载资源。

Spring如何获取url spring如何获取dn_java_11

如何获取XML的校验类型

DTD和XSD声明文件都是通过相应的EntityREsolver实现类来实现的。那spring是如何知道当前解析的xml文件,是DTD类型还是XSD类型呢?

我们回到之前的doLoadDocument方法。

Spring如何获取url spring如何获取dn_Spring如何获取url_12


我们到getValidationModeForResource方法中,看下xml文件的校验类型是如何判断的。

Spring如何获取url spring如何获取dn_xml文件_13


首先会通过getValidationMode方法获取的校验模式,默认的校验模式就是VALIDATION_AUTO,所以不会走第一个分支,我们看下detectValidationMode方法,看它是如何自动检测xml校验类型的:

Spring如何获取url spring如何获取dn_Spring如何获取url_14


可以看到,在detectValidationMode方法中,首先获取Resource资源的输入流,然后又委托给了XmlValidationModeDetector的detectValidationMode方法去检测了。我们继续进入XmlValidationModeDetector的detectValidationMode方法看下:

Spring如何获取url spring如何获取dn_spring_15


首先将输入流InputStream封装为一个可以缓冲的字符流,然后下面有个hasDocType方法来判断文件中是否包含“DOCTYPE” 。也就是说,如果检测到xml的内容中,包含“DOCTYPE” 字符串,就认定xml文件的校验方法为DTD,否则就是XSD。这样spring就可以根据具体的校验类型,分别使用不同的解析器去获取相应的校验文件。

下面总结下我们今天的内容:

Spring如何获取url spring如何获取dn_java_16