先列下原配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
运行时异常
2020-01-10 11:28:07.822-[WARN] org.springframework.util.xml.SimpleSaxErrorHandler.warning(SimpleSaxErrorHandler.java:48) Ignored XML validation warning
org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'http://www.springframework.org/schema/beans/spring-beans.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source) ~[xercesImpl-2.9.1.jar:?]
显示不能读取到 'http://www.springframework.org/schema/beans/spring-beans.xsd'
于是在网上查询相关信息, 大概是在 http://www.springframework.org/schema/beans/spring-beans.xsd 这个配置可以加序列号和不加序列号, 加序列号会加载到特定版本的xsd , 不加版本包会加载到当前版本的xsd ,笔者用的版本是5.1.7。(优先本地加载, 本地加载不到会到sping的官网加载,笔者出现的错误是在屏蔽spring官网的情况下,为了模拟线上机房不能连接外网的情况)但是为什么加载不到本地文件呢,去查询相关资料 。
在spring源码的DelegatingEntityResolver类中,看到看到spring通过xml加载bean的时候会判断是DTD规范还是xsd规范 , 我们用的是xsd :
进入 resolveEntity 方法,发现会以systemId为key根据一个map获取资源位置:
进入方法看下具体的map, 是一个size为254的map,
查看SystemId在这个map对应的key——value ,竟然是 org/springframework/beans/factory/xml/spring-beans-4.1.xsd
了解spring通过xml加载bean机制的同学应该知道, 这些这个map是从spring的spring.schema配置里加载的,代码也印证了这一点,会默认从 META-INF/spring.schemas 加载
看下我们5.1.7的spring.schema配置,发现无论是否有版本号都只指向一个文件
org/springframework/beans/factory/xml/spring-beans.xsd
打开5.1.7的jar包发现也确实只有这一个文件
目前看来事情的元凶是加载的时候需要找到spring-beans-4.1.xsd文件,但是我们的jar中不存在,所以抛出了异常
事情到这里很奇怪了,为什么spring对应的schemaMap会指向org/springframework/beans/factory/xml/spring-beans-4.1.xsd ,继续跟踪:
在idea中搜索 spring.schema 会发下找到十余个文件,这个笔者猜想是spring在加载配置时候,spring是把所有的文件依次加载进这个Map中, 由于key出现了冲突,最终展现的map没有完全按照5.1.7包下的配置, 至于在加载过程中发生了什么, 如何调整加载顺序,笔者现在对classLoader还不熟悉,暂时无法给出解答。
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, this.classLoader);
最终的解决方式是在map中找到一个value为对应文件的key, 将spring bean的xml配置修改为这个key,就会指向对应的文件:
由于时间有限,最终加载过程还是没有探究清楚,日后再查。