2017-02-09 243 views
4

在我看來,Maven依賴插件在計算依賴列表時行爲異常。maven依賴項插件忽略依賴項版本?

假定這3個項目:

BASE1:

<?xml version="1.0" encoding="UTF-8"?>                                
<project> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>mygroup</groupId> 
    <artifactId>base1</artifactId> 
    <version>1.0-SNAPSHOT</version> 
    <packaging>jar</packaging> 

    <dependencies> 
     <dependency> 
     <groupId>commons-lang</groupId> 
     <artifactId>commons-lang</artifactId> 
     <version>2.3</version> 
     </dependency> 
    </dependencies> 
</project> 

BASE2:

<?xml version="1.0" encoding="UTF-8"?>                                
<project> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>mygroup</groupId> 
    <artifactId>base2</artifactId> 
    <version>1.0-SNAPSHOT</version> 
    <packaging>jar</packaging> 

    <dependencies> 
     <dependency> 
     <groupId>commons-lang</groupId> 
     <artifactId>commons-lang</artifactId> 
     <version>2.6</version> 
     </dependency> 
    </dependencies> 
</project> 

組合:

<?xml version="1.0" encoding="UTF-8"?>                                
<project> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>mygroup</groupId> 
    <artifactId>combined</artifactId> 
    <version>1.0-SNAPSHOT</version> 
    <packaging>jar</packaging> 

    <dependencies> 
     <dependency> 
     <groupId>mygroup</groupId> 
     <artifactId>base1</artifactId> 
     <version>1.0-SNAPSHOT</version> 
     </dependency> 
     <dependency> 
     <groupId>mygroup</groupId> 
     <artifactId>base2</artifactId> 
     <version>1.0-SNAPSHOT</version> 
     </dependency> 
    </dependencies> 
</project> 

兩者,BASE1和BASE2取決於公地琅,但每個人都不一樣版本! 組合取決於base1和base2。

在聯合調用mvn dependency:list時,我期望在版本2.3和2.6中看到base1,base2和commons-lang,因爲兩者都被使用。 但是實際的輸出是:

[INFO] The following files have been resolved: 
[INFO] commons-lang:commons-lang:jar:2.3:compile 
[INFO] mygroup:base1:jar:1.0-SNAPSHOT:compile 
[INFO] mygroup:base2:jar:1.0-SNAPSHOT:compile 

它甚至沒有使用常見的琅最高版本號,但只是一個首先發現。

我該如何避免這種情況?我需要所有的依賴關係。

+0

最適合你的是改變需要依賴commons-lang:2.3的代碼。對不起...... – otonglet

+0

@otonglet如果base1和base2是第三方模塊,我不能這樣做。 – radlan

+0

@radlan你有沒有把mvn依賴:list與['mvn dependency:tree'](https://maven.apache.org/plugins/maven-dependency-plugin/tree-mojo.html)混淆? – nullpointer

回答

3

根據這個official documentation(與相關部分以粗體突出):

依賴調解 - 這決定了遇到多個版本的工件時將使用哪個版本的依賴關係。目前,Maven 2.0只支持使用「最接近的定義」,這意味着它將在依賴關係樹中使用最接近依賴項的版本。您可以通過在項目的POM中明確聲明版本來保證版本。 請注意,如果兩個依賴版本在依賴關係樹中處於相同深度,直到Maven 2.0.8未定義哪一個會獲勝,但自從Maven 2.0.9以來,這是聲明中的順序:第一次聲明獲勝。

因此,Maven選擇2.3版本,因爲它在依賴關係解析過程中首先遇到。請注意,如果您在combined模塊上運行mvn dependency:tree,它將顯示使用哪個版本以及哪個版本被省略。

最好的解決辦法是,在其POM聲明的依賴性明確接你在combined神器所需的版本,這樣的Maven有利於它在其它版本:

<?xml version="1.0" encoding="UTF-8"?> 
<project> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>mygroup</groupId> 
    <artifactId>combined</artifactId> 
    <version>1.0-SNAPSHOT</version> 
    <packaging>jar</packaging> 

    <dependencies> 
    <dependency> 
     <groupId>mygroup</groupId> 
     <artifactId>base1</artifactId> 
     <version>1.0-SNAPSHOT</version> 
    </dependency> 
    <dependency> 
     <groupId>mygroup</groupId> 
     <artifactId>base2</artifactId> 
     <version>1.0-SNAPSHOT</version> 
    </dependency> 
    <dependency> <!-- This will override the versions in base1 and base2 --> 
     <groupId>commons-lang</groupId> 
     <artifactId>commons-lang</artifactId> 
     <version>2.6</version> 
    </dependency> 
    </dependencies> 

注意的Maven不能選擇兩個版本,因爲在這種情況下,項目類路徑中的相同類會有兩個定義,這會在運行時導致意外問題。

+0

其實這似乎是唯一的解決方案。這並不是我想要的,因爲例如base1和base2是可執行應用程序,其classpath是在構建時生成的,對於那些組裝所有依賴項的應用程序只是一個_container_,base2將不可運行,因爲它的類路徑不包含在組裝的依賴項中。但是,看起來我被困在這裏,你的提議可能是最好的解決方案。 – radlan

+0

@radlan我可能會錯過一些東西,但根據你的描述你說的「base1和base2是可執行的應用程序」,似乎你應該將構建分成兩個獨立的構建,其中構建#1構建base1和構建#2構建base2,在這種情況下,每個版本都使用它自己的獨立版本的依賴關係。無論如何,這裏是一個似乎相關的帖子:http://stackoverflow.com/questions/24962607/multiple-versions-of-the-same-dependency-in-maven。我碰巧也回答了它。在這種情況下,您可以使用Maven配置文件。每個配置文件都可以聲明自己的依賴關係。 – manouti

+0

base1和base2有單獨的版本。但是還有另一種構建方式,將其他構建捆綁在一起,以簡化整個bundle的部署。 – radlan

1

Maven從上到下掃描pom,並使用它遇到的第一個版本。

假設你真的需要兩個版本的commons-lang,你可以把這兩個版本放在你的項目中,並用maven把它們打包到你的jar中。

但是,編譯器如何知道調用StringUtils.isEmpty()是否調用2.3或2.6版本?

Same discussion here