模板網(wǎng)站制作成都百度推廣優(yōu)化創(chuàng)意
1、前因
今天在生產(chǎn)環(huán)境啟用了某個功能,結(jié)果發(fā)現(xiàn)有個文件上傳華為云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 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修復(fù)
知道了問題所在,接下來就是要找到那個正確的類,我們進到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)境當(dāng)時測的時候沒有指定實現(xiàn)類也沒有報錯,文件也正常上傳到了華為云OBS上,但是這個問題發(fā)生后,再在測試環(huán)境就沒法復(fù)現(xiàn)這個問題了,所以也沒有再深究。
找到問題了,我們在引入OBS的jar包時是這樣寫的:
<dependency><groupId>com.huaweicloud</groupId><artifactId>esdk-obs-java-bundle</artifactId><version>[3.21.8,)</version>
</dependency>
這種寫法會導(dǎo)致使用最新版本的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,所以也不會有上面所說的問題。