spring验证xml文件文件的过程
获取xsd文件信息
spring中使用xsd文件定义bean标签元素,spring容器加载xml配置文件时,会先获取xsd文件去验证xml文件的正确性。
获取xsd文件可直接请求xsd文件的URL即可,但是在生产环境往往不可访问公网,或者由于网络的抖动导致请求的不可达,导致请求xsd文件出错,进而导致整个spring容器初始化失败;为避免这个问题,spring将对应的xsd文件放到本地jar中,容器初始化时优先从本地加载。
xsd文件定义一般定义在/META-INF/spring.schemas文件中,例如spring-data-commons-2.1.10.RELEASE.jar中的spring.schemas提供了了根据xsd文件的url映射到对应的xsd文件的信息。
这个spring在解析xml文件拿到对应的xsd的url后,就可以根据上面的信息找到xsd文件了,不用通过网络请求,然后就行可解析xsd文件元整xml文件的的正确性。
xsd文件的加载和寻找过程
查看springframwork源码PluggableSchemaResolver类定义了加载/META-INF/spring.schemas文件的过程,加载全部jar中的/META-INF/spring.schemas并将xsd的url和在jar中的路径保存在map中,在解析时直接根据xsd的url去map中寻找xsd文件的位置来获取。
PluggableSchemaResolver.java
问题描述
软件版本信息
spring framework:4.3.13.RELEASE
spring ldap:2.3.2.RELEASE
功能背景
ldap方式查询公司人员信息
主要实现代码
UserDao.java
UserDaoImpl.java
UserDaoTest.java
问题描述
上面的程序在本地机器上运行正常,发布到开发测试机上,抛出异常。
异常堆栈
org.xml.sax.SAXParseException; systemId: http://www.springframework.org/schema/ldap/spring-ldap.xsd; lineNumber: 9; columnNumber: 112; schema_reference.4: 无法读取方案文档 'http://www.springframework.org/schema/data/repository/spring-repository.xsd', 原因为 1) 无法找到文档; 2) 无法读取文档; 3) 文档的根元素不是。
问题排查和定位
从异常信息看,是获取和解析spring-repository.xsd文件出错,但是为什么会需要spring-repository.xsd呢?
于是想到在spring容器初始化的过程中,需要解析xsd文件以验证xml文件格式的正确与否,获取和解析spring-repository.xsd出错应该是在这个过程中出现的。
项目中并没有使用到spring-repository.xsd中定义的任何标签,为什么会加载它呢?
初步怀疑是存在jar包依赖,但是检查后并不存在包含spring-repository.xsd文件的spring-data-commons的jar包;但是打开spring-ldap.xsd文件发现有如下代码:
到此恍然大悟,原来是spring-ldap.xsd中又引用到spring-repository.xsd中的标签定义,所以解析时才回去找spring-repository.xsd文件,但本地没有spring-data-commons的jar包,所以才会尝试请求http://www.springframework.org/schema/data/repository/spring-repository.xsd 获取文件内容,但是开发环境的机器不能链接公网,而本地机器可以,所以才出现了上面的问题。
于是,想着只要在在pom.xml中添加spring-data-commons的jar包依赖,问题就应该解决了吧。然而,并没有,依旧是本地机器可以,开发测试环境的机器依旧报上面的异常。
查看spring-data-commons的jar包中的/META-INF/spring.schemas定义,如下:
发现,spring.schemas中的xsd文件url使用的是https,而在spring-ldap.xsd文件中引用的spring-repository.xsd文件的schemaLocation是http的,二者不一致,导致了去根据http的xsd文件url到map中找xsd文件路径时找不到。本地找不到之后,spring便尝试网络请求获取,而恰好网络请求不可达。
经过debug后,进一步确认了我的问题定位:
到此,定位到该问题为spring-ldap项目的bug,spring-ldap.xsd文件中引用的spring-repository.xsd文件的schemaLocation应该是https的。目前该问题已经在GitHub的spring-ldap上提出了issue等待解决。
问题解决方法
不使用spring自定义的ldap:标签元素,改为最基础的bean标签,这样就不会加载和解析spring-ldap.xsd文件了,最终的xml文件内用如下:
联系客服