自定义LSResourceResolver引发XML Schema重复全局组件错误求助
核心原因推测
这种重复全局组件的错误,大概率是自定义LSResourceResolver的实现逻辑存在问题,导致Schema解析器重复加载了同一个XSD文件,或者错误返回了不符合预期的Schema内容。以下是具体排查方向:
未做Schema加载缓存,重复返回同一文件的输入流
当处理嵌套引用(比如Employee.xsd引用Person.xsd,Person.xsd又间接引用Employee.xsd)时,如果Resolver每次收到请求都重新读取并返回新的输入流,Schema解析器会认为这是两个不同的Schema文件,但它们包含同名的全局组件,从而抛出重复定义错误。而默认Resolver通常会内置缓存机制,自动跳过已加载的Schema。引用路径解析逻辑错误
检查Resolver中处理systemId(即XSD里的引用路径)的逻辑:比如Employee.xsd里用<xs:import schemaLocation="Person.xsd"/>,但Resolver没有根据当前Schema的路径去寻找对应的Person.xsd,反而错误返回了Employee.xsd的内容,就会导致解析器反复加载同一个文件,触发重复定义。Schema内容读取异常
确认Resolver返回的输入流对应的XSD内容是否正确:比如是否因为文件路径拼接错误,读取到了错误的XSD文件,或者读取过程中出现IO问题导致内容重复/错乱,使得解析器识别到重复的全局组件。解析器配置冲突
部分Schema解析器(如Apache Xerces)在使用自定义Resolver时,需要手动开启缓存或配置相关属性。如果你的代码里禁用了解析器的内置缓存,或者Resolver的实现与解析器的默认逻辑冲突,也会导致重复加载问题。
验证与修复步骤
添加日志排查请求明细
在resolveResource方法中打印每次请求的namespaceURI、publicId、systemId参数,看看是否存在重复请求同一个Schema的情况,或者请求的路径是否符合预期。临时添加缓存机制
在Resolver里维护一个Map,以文件路径或systemId为key,缓存已经加载过的输入流(或文件内容),同一个请求只返回一次缓存的内容,验证是否能解决错误。示例伪代码:private Map<String, InputStream> schemaCache = new HashMap<>(); @Override public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { String cacheKey = systemId + namespaceURI; if (schemaCache.containsKey(cacheKey)) { // 返回缓存的输入流(注意重置流的位置) InputStream cachedStream = schemaCache.get(cacheKey); cachedStream.reset(); return createLSInput(cachedStream, publicId, systemId); } // 读取文件并缓存 InputStream stream = loadSchemaFromMocks(systemId, baseURI); schemaCache.put(cacheKey, stream); return createLSInput(stream, publicId, systemId); }校验返回的Schema内容
临时在Resolver中读取文件后,将内容打印出来,确认返回的是预期的XSD文件,没有出现内容重复或错误的情况。检查解析器配置
确认创建SchemaFactory时的配置,比如是否设置了http://apache.org/xml/features/validation/schema-full-checking等属性,是否与自定义Resolver存在冲突。可以尝试恢复默认配置,只添加自定义Resolver,看是否能正常运行。
内容的提问来源于stack exchange,提问作者donald

