Xerces是Java生态圈使用最廣泛的XML解析器,基本上所有的類庫和架構都會在一定程度上使用它(即使沒有直接引用,也有可能間接引用)
Xerces在官網中釋出的包是沒有标注版本的,2.11.0的jar命名為xercesImpl.jar而不是xercesImpl-2.11.0.jar.
Xerces不使用Maven,不會上傳官方的release版本到Maven的中央倉庫。
Xerces以前是釋出一個jar包,但是之後分成兩個jar包釋出,一個包含API的xml-apis.jar和另一個包含其實作的xercesImpl.jar。許多老點兒的Maven Pom仍然依賴xerces.jar。更早的時候Xerces釋出一個xmlParserAPIs.jar,也有些很古老很古老的pom會依賴這個jar。
釋出到Maven倉庫的一些jar經常會依賴版本不同的xml-apis和xercesImpl。舉例來說,依賴的xml-apis的版本可能是1.3.03而依賴的xercesImpl版本可能就是2.8.0,即使兩個包都是來自
Xerces 2.8.0。因為人們使用xml-apis.jar隻想使用它某個版本的特定的API。
更麻煩的是,JRE中JAXP(Java API for XML Processing)的Reference implementation(參考實作?)使用的XML解析器就是用的這個鳥Xerces。實作類被重新打包進了com.sun.,進而導緻直接引用這些類很危險,因為他們在某些JRE中可能不會包含。然而,Xerces中并不是所有的方法都通過java.和javax.*的API暴露。舉例來說,就沒有實作Xerces序列化的API。
基本上所有的servlet容器(JBoss, Jetty, Glassfish, Tomcat, ====),都包含一份或多份Xerces在他們的/lib包下。
舉例來說,A組織可能以如下方式依賴xml-apis:
<code><groupId>org.apache.xerces</groupId> <artifactId>xml-apis</artifactId> <version>2.9.1</version></code>
而B組織可能以如下方式依賴同樣的jar包:
<code><groupId>xml-apis</groupId> <artifactId>xml-apis</artifactId> <version>1.3.04</version></code>
盡管B的jar版本比A的jar版本低,但是maven并不知道他們倆是同一個artifact,因為兩個jar的groupId不同,那麼,最後maven解決版本的沖突而是把兩個jar同時引入項目。如下圖:
删除servlet中的Xerces,然後祈禱你的容器可以在JAXP提供的版本上運作。
保留servlet中的那個版本,然後祈禱你的應用架構可以在servlet提供的Xerces版本上正常運作。
如果最後你的産品有那麼一個或者兩個沒解決的版本沖突(如果你的應用很大的話,這是很容易出現的情況),你很快就會發現你正處于類加載器地獄(ClassLoader Hell),疑惑類加載器到底他媽的挑了那個版本在運作?在window或者linux上會不會挑同一個版本(很有可能不會)。
我們嘗試把所有的Xerces的maven依賴标記成 或者,但是由于這鳥貨的别名太多了(xml-apis, xerces, xercesImpl, xmlParserAPIs,====),這有時候并無卵用。另外,我們依賴的第三方包或者架構很可能不會跑在JAXP的版本或者servlet容器提供的Xerces版本上。
到底怎麼解決?
目前他們的解決方案如下:
可以嘗試使用maven enforcer插件中的banned dependency。這個rule可以讓你禁止所有你不喜歡的别名,而且隻會加入你喜歡的。