1. 程式人生 > >Java包衝突常見解決方法

Java包衝突常見解決方法

Java的好處之一是有大量的庫可供開發者使用,然而,這些庫通常都有較多版本,並且也往往會依賴其他的庫。 使用Maven或者其他構建工具時,經常需要將這些依賴打包成一個Jar包,或者自己的Jar包與其他的Jar包同時放到Classpath中。 這些時候,很容易就會產生一個常見的問題,就是依賴的庫不同的版本間會有衝突。

具體說來,如果專案程式碼同時依賴於庫A和庫B,庫A和庫B又依賴不同版本的庫C。 如果庫C不同版本間的函式簽名或者實現上有差別,或是某個類的成員final等的修飾不同,就可能會出現如下兩類異常。

  1. Method Not Found Exception
  2. Cannot Overwrite final …

解決這些衝突的第一步是定位問題,找到庫C兩個版本之間,衝突的原因是什麼。 是新的版本刪除或者添加了新的函式?還是新的版本把final關鍵字刪了,還是把以前的非final的成員變成final了?

定位問題之後,最簡單的解決方法就是,看看是否能夠調整庫A或庫B的版本,使它們依賴的庫C的版本能夠相容。

大多數時候,我們不能調整庫A或庫B的版本,或者這兩個庫的任何版本組合都不同使依賴的庫C能夠相容。 我們需要進一步分析產生衝突的原因,區分清楚衝突究竟是屬於以下三種情況中的哪一種,再分別解決:

  1. 庫A和庫B用到的庫C的函式在兩個版本中都存在並且簽名一致。這種情況下,衝突產生的原因應該是C不同版本之間實現方法有區別。 例如庫A呼叫了庫C版本1中類File的open方法,該方法又呼叫類FileImpl的open(String path)方法,而在庫C的版本2中類File的open方法呼叫的是FileImpl的open(URI path)函式,由於函式簽名不一樣,載入了版本1的File類和版本2的FileImpl類,就會產生衝突。在這種情況下,可以顯式的exclude掉庫A或者庫B中的對庫C的依賴,只使用其中的一個版本。
  2. 庫A中用到的函式在庫C兩個版本中都存在,庫B用到的函式在另一個版本中不存在。例如庫A用到的函式File.open()在兩個版本中都存在,但是庫B中用到的函式File.safeOpen()只在庫B所依賴的版本中存在。 這種情況下, 我們需要exclude掉庫A對庫C的依賴,只使用庫B中使用的版本。
  3. 庫A和庫B用到的函式都只存在於各自依賴的版本中。這種情況下,需要去尋找看看是否存在另一個版本,裡面能相容庫A和庫B的函式呼叫。如果可以,則將庫A和庫B對庫C的依賴都exclude,引入該版本。如果不存在,則只能讓兩個版本同時出現,這個時候只能採用Shade大法了。