天天看點

一個讓java程式員有殺人的沖動的Xerces沖突問題

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>&lt;groupId&gt;org.apache.xerces&lt;/groupId&gt; &lt;artifactId&gt;xml-apis&lt;/artifactId&gt; &lt;version&gt;2.9.1&lt;/version&gt;</code>

而B組織可能以如下方式依賴同樣的jar包:

<code>&lt;groupId&gt;xml-apis&lt;/groupId&gt; &lt;artifactId&gt;xml-apis&lt;/artifactId&gt; &lt;version&gt;1.3.04&lt;/version&gt;</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可以讓你禁止所有你不喜歡的别名,而且隻會加入你喜歡的。