1、前因
今天在生產(chǎn)環(huán)境啟用了某個功能,結(jié)果發(fā)現(xiàn)有個文件上傳華為云OBS失敗了,報錯如下:
Caused by: java.lang.IllegalArgumentException: 不支持:http://javax.xml.XMLConstants/property/accessExternalDTD
at 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 more
2、BUG定位
首先看拋異常的第一條信息,org.apache.xalan.processor.TransformerFactoryImpl,這個類首先看名稱,后面帶了Impl,一般來說應(yīng)該是某個接口的實現(xiàn)類,因為這個是引用的jar包里報的錯,還是apache的jar包,一般來說不太可能是apache代碼寫錯了,所以很有可能是我們調(diào)這個接口的時候,調(diào)錯實現(xiàn)類了,實際上不應(yīng)該調(diào)apache的這個實現(xiàn)類。
直接來看調(diào)用方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是個抽象類,整個方法中也沒有指定使用到底用哪個實現(xiàn)類,這個時候就應(yīng)該想到Java的SPI機制了,打開org.apache.xalan.processor.TransformerFactoryImpl所在Jar包,Jar包里有個文件夾META-INF,里面有個services的文件夾,這里面的文件,就指定了程序會使用TransformerFactory的哪個實現(xiàn)類,如下圖:
打開該文件,文件內(nèi)容如下:
org.apache.xalan.processor.TransformerFactoryImpl
由于我們的程序里沒有相應(yīng)的SPI配置,所以程序會優(yōu)先使用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,如圖:
文件內(nèi)容如下:
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
再啟動服務(wù)時,服務(wù)就正常了
4、疑惑
眼尖的小伙伴可能會發(fā)現(xiàn),我這個異常是在生產(chǎn)環(huán)境拋出來的,難道我之前測試環(huán)境沒測出來這個問題嗎,是的,測試環(huán)境當時測的時候沒有指定實現(xiàn)類也沒有報錯,文件也正常上傳到了華為云OBS上,但是這個問題發(fā)生后,再在測試環(huán)境就沒法復現(xiàn)這個問題了,所以也沒有再深究。
找到問題了,我們在引入OBS的jar包時是這樣寫的:文章來源:http://www.zghlxwxcb.cn/news/detail-823576.html
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java-bundle</artifactId>
<version>[3.21.8,)</version>
</dependency>
這種寫法會導致使用最新版本的jar包,來看jar包的發(fā)布時間:
我們測試的時候大概是在十月份,十一月、十二月都有過發(fā)布,功能啟用時間更是在后面,所以我們測試的jar跟生產(chǎn)的jar實際上版本是不一樣的,生產(chǎn)是3.23.9.1,而測試是3.23.9,我們將版本指定為3.23.9后查看com.obs.services.internal.xml.OBSXMLBuilder源碼,里面并沒有使用抽象類TransformerFactory,所以也不會有上面所說的問題。文章來源地址http://www.zghlxwxcb.cn/news/detail-823576.html
到了這里,關(guān)于記一次SPI機制導致的BUG定位【不支持:http://javax.xml.XMLConstants/property/accessExternalDTD】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!