2014-09-23 157 views
2

我正在爲Java中的ERP系統進行定製。在我的定製中,我想使用Apache POI 3.10.1。因此,我整合了罐子poi-3.10.1-20140818.jar和poi-ooxml-3.10.1-20140818.jar。如何包含兩個不同版本的相同依賴項?

但是,這些罐子包含幾個已經包含在ERP系統核心代碼中的類別,但有所不同。

如果核心ERP類覆蓋了POI類,則定製會引發運行時異常。如果POI類覆蓋核心類,則核心功能可能也會發生同樣的情況。

處理類似問題的最佳做法是什麼?

我的自定義是一個相對獨立的功能。

回答

5

有兩種方法來解決這個問題:

  1. 您可以從加載POI的其他版本的ClassLoader庫隔離。現在,我假設ERP系統在類路徑上,這樣您需要將庫與系統類加載器隔離。你可以通過創建一個URLClassLoader的新實例來實現,然後你指向包含更新版本POI的jar文件。確保還要添加all transient dependencies,例如commons-codec以避免類加載問題。另外請注意,瞬態依賴關係本身可能具有瞬態依賴關係。

    爲了隱藏一個類加載器的類路徑中,您將設置引導類加載器作爲由null代表的直接父:

    new URLClassLoader(new URL[]{ new URL("poi-3.10.1-20140818.jar"), ... }, null); 
    

    有了這個類加載器,你可以查詢該較新版本的POI類似

    Class.forName("org.apache.poi.hssf.usermodel.HSSFWorkbook", true, urlClassLoader); 
    

    用於檢索新版本的HSSFWorkbook。但是請注意,任何直接引用HSSFWorkbook的文字都可以通過執行類的類加載器來解決,該類加載器當然會鏈接舊的不兼容版本的類。因此,您需要對所有代碼使用反射。或者,您可以向URLCLassLoader添加一個包含所有邏輯的類,並僅通過反射調用此類。一般而言,這是一種更清潔的方法。例如,您可以添加一個類實現的自舉類如Callable你那麼可以從任何不同的上下文中使用,例如:或者

    Callable<File> sub = (Callable<File>) Class.forName("pkg.Subroutine", 
                    true, 
                    urlClassLoader); 
    File convertedFile = sub.call(); 
    
  2. ,你可以重新打包第二POI依賴到另一個名字空間。做完這些之後,這些類不再相互衝突,因爲它們的名稱不再相同。這可能是一種更清潔的方法,因爲您可以使用來自同一個類加載器的兩個庫,並避免反射。

    要重新打包一個依賴項到另一個名稱空間中,有一些工具可以幫助您完成此任務,如Maven Shade plugin。對於antShadow pluginGradle,替代方案爲jarjar

相關問題