网站开发需求,廊坊永清网站建设,爱查企业,17网店货源网1、前因
今天在生产环境启用了某个功能#xff0c;结果发现有个文件上传华为云OBS失败了#xff0c;报错如下#xff1a;
Caused by: java.lang.IllegalArgumentException: 不支持#xff1a;http://javax.xml.XMLConstants/property/accessExternalDTDat org.apache.xal…1、前因
今天在生产环境启用了某个功能结果发现有个文件上传华为云OBS失败了报错如下
Caused by: java.lang.IllegalArgumentException: 不支持http://javax.xml.XMLConstants/property/accessExternalDTDat org.apache.xalan.processor.TransformerFactoryImpl.setAttribute(TransformerFactoryImpl.java:576) ~[xalan-2.7.1.jar:?]at com.obs.services.internal.xml.OBSXMLBuilder.asString(OBSXMLBuilder.java:306) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.internal.V2Convertor.transCompleteMultipartUpload(V2Convertor.java:96) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.internal.service.ObsMultipartObjectService.completeMultipartUploadImpl(ObsMultipartObjectService.java:96) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.AbstractMultipartObjectClient.access$400(AbstractMultipartObjectClient.java:39) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.AbstractMultipartObjectClient$5.action(AbstractMultipartObjectClient.java:185) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.AbstractMultipartObjectClient$5.action(AbstractMultipartObjectClient.java:182) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]at com.obs.services.AbstractClient.doActionWithResult(AbstractClient.java:388) ~[esdk-obs-java-bundle-3.23.9.1.jar:?]... 50 more2、BUG定位
首先看抛异常的第一条信息org.apache.xalan.processor.TransformerFactoryImpl这个类首先看名称后面带了Impl一般来说应该是某个接口的实现类因为这个是引用的jar包里报的错还是apache的jar包一般来说不太可能是apache代码写错了所以很有可能是我们调这个接口的时候调错实现类了实际上不应该调apache的这个实现类。
直接来看调用方com.obs.services.internal.xml.OBSXMLBuilder的asString方法
public String asString() throws TransformerException {TransformerFactory tf TransformerFactory.newInstance();tf.setAttribute(http://javax.xml.XMLConstants/property/accessExternalDTD, );tf.setAttribute(http://javax.xml.XMLConstants/property/accessExternalStylesheet, );Transformer transformer tf.newTransformer();transformer.setOutputProperty(omit-xml-declaration, yes);StringWriter writer new StringWriter();transformer.transform(new DOMSource(this.getDocument()), new StreamResult(writer));return writer.getBuffer().toString().replaceAll(|\r, );
}代码里的TransformerFactory是个抽象类整个方法中也没有指定使用到底用哪个实现类这个时候就应该想到Java的SPI机制了打开org.apache.xalan.processor.TransformerFactoryImpl所在Jar包Jar包里有个文件夹META-INF里面有个services的文件夹这里面的文件就指定了程序会使用TransformerFactory的哪个实现类如下图 打开该文件文件内容如下
org.apache.xalan.processor.TransformerFactoryImpl由于我们的程序里没有相应的SPI配置所以程序会优先使用org.apache.xalan.processor.TransformerFactoryImpl类
3、BUG修复
知道了问题所在接下来就是要找到那个正确的类我们进到TransformerFactory这个类里由于我用的是IDEA点类边上的蓝色按钮就可以找到这个类的子类如下图 可以看到同样叫TransformerFactoryImpl名字的还有com.sun.org.apache.xalan.internal.xsltc.trax包下的类然后我们就在项目的META-INF的目录下新增services目录如果没有的话在该目录下新增文件javax.xml.transform.TransformerFactory如图 文件内容如下
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl再启动服务时服务就正常了
4、疑惑
眼尖的小伙伴可能会发现我这个异常是在生产环境抛出来的难道我之前测试环境没测出来这个问题吗是的测试环境当时测的时候没有指定实现类也没有报错文件也正常上传到了华为云OBS上但是这个问题发生后再在测试环境就没法复现这个问题了所以也没有再深究。 找到问题了我们在引入OBS的jar包时是这样写的
dependencygroupIdcom.huaweicloud/groupIdartifactIdesdk-obs-java-bundle/artifactIdversion[3.21.8,)/version
/dependency这种写法会导致使用最新版本的jar包来看jar包的发布时间 我们测试的时候大概是在十月份十一月、十二月都有过发布功能启用时间更是在后面所以我们测试的jar跟生产的jar实际上版本是不一样的生产是3.23.9.1而测试是3.23.9我们将版本指定为3.23.9后查看com.obs.services.internal.xml.OBSXMLBuilder源码里面并没有使用抽象类TransformerFactory所以也不会有上面所说的问题。