1. 程式人生 > >java 包衝突解決方法

java 包衝突解決方法

1、診斷包衝突

java.lang.NoSuchMethodError: org.apache.commons.io.output.DeferredFileOutputStream.<init>(ILjava/lang/String;Ljava/lang/String;Ljava/io/File;)V

2、解決

2.1 可見的依賴衝突

在eclipse中開啟工程,在pom檔案的dependency hierarchy中,搜衝突的包commons-io,檢視各依賴包的依賴資訊。包有依賴衝突的話,會有顯示xxx版本與xxx版本衝突。選擇正確的版本,將剩下的版本在對應的引用包下exclusion掉。

或者用 mvn dependency:tree > tree.log,將依賴資訊匯入檔案tree.log中,檢視包commons-io的依賴資訊。

如果執行失敗,報錯:outofMemery

執行命令:

set MAVEN_OPTS=-Xmx512m -XX:MaxPermSize=128m
linux系統執行:
export MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=128m"
然後再mvn dependency:tree > tree.log即可。

2.2 不可見的依賴衝突

1)檢視伺服器使用的jboss路徑下有沒有包含衝突的包的其他版本。

路徑是:jboss-x.x.x.GA/lib, 和 jboss-x.x.x.GA/server/default/lib ,如果裡面有衝突的版本,則刪除。

2)檢視異常發生時,JVM載入的是哪個包。

在程式啟動的指令碼中加入JVM啟動引數 -verbose:class,然後重啟應用。在啟動日誌中可以看到載入的類來自哪個包。

[Loaded org.apache.velocity.runtime.parser.node.ASTTrue from file:/home/admin/app/.default/deploy/app.war/WEB-INF/lib/velocity-1.6.4.jar]

如果在jboos的啟動日誌中沒有發現載入衝突的類,可能是懶載入。
執行觸發異常的操作,再看jboss的啟動日誌,這時就有載入類的資訊了。

檢視載入的類所在的包,與正確的包比較。

補充:

出現這種情況,有可能是包的版本引發的錯誤,所呼叫的方法在高版本和低版本的實現不一樣,或者在某一版本中,方法有缺失。

也有可能是,兩個不同的jar包,裡面含有相同路徑的類,然後在呼叫過程中混淆了。這種情況,可以在eclipse中使用shift+ctrl+T,檢視工程中有多少個這樣的類,檢視類路徑資訊。

3)找到引發異常的包(比如A)之後,再回到工程裡面,執行mvn dependency:tree > tree.log
在tree.log裡面查詢A包的依賴資訊,然後在頂層包的依賴中排除掉A包即可。

demo,如果在依賴樹中也沒找到依賴資訊。很可能是其他路徑引入進來的(我不知道了。。),要解決的話,就要把A包全域性排除掉,不要讓它打進包中。
a.網上搜了一下,有一個maven外掛,按照配置了一下,未果。
b.找到一個簡單的方法,直接在父工程pom檔案中加入此包的依賴,然後設定scope屬性。
即:

<dependency>
  <groupId>A.groupID</groupId>
  <artifactId>A.artifactId</artifactId>

  <version>1.2.7</version>

<scope>provided</scope>

</dependency>

c.在maven庫中查詢A包的其他版本,看看有沒有空包版本,名字如not-exist等。然後再如工程pom中依賴此包。

maven新增依賴的時候,會優先載入高版本的jar包,如果依賴的這個包是空的,自然不會調裡面的類或方法


關於scope,可以參考這個:http://supercharles888.blog.51cto.com/609344/981316
http://drizzlewalk.blog.51cto.com/2203401/665590
compile 預設範圍,一直有用。
provided 編譯時用,不會被打入jar包
runtime 編譯的時候不需要,執行和測試的時候需要。
test 只在測試編譯和測試執行時需要
system 需要制定一個本地路徑,基於本地物件編譯,不推薦使用。

唉,菜鳥之路……