依赖传递

当A依赖B,B依赖C时,如果B中C的scope是provided或test,那么A不依赖C;否则A依赖C,scope与B中C的scope相同,这种行为就是依赖传递。此时,如果A也依赖C,那么A中不用声明对C的依赖,maven会自动处理项目之间的依赖关系。
可以通过mvn dependency:tree命令查看工程的依赖树,比如:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ ProjectA ---
[INFO] cn.timd:ProjectA:jar:1.0-SNAPSHOT
[INFO] +- cn.timd:ProjectB:jar:1.0-SNAPSHOT:compile
[INFO] |  \- cn.timd:ProjectC:jar:1.0-SNAPSHOT:compile
[INFO] \- junit:junit:jar:3.8.1:test
依赖冲突

依赖冲突是指项目最终依赖相同artifact的多个版本。比如:A依赖B 和 C,B依赖E的1.0版本,C依赖D,D依赖E的2.0版本。此时A就依赖E的1.0和2.0版本。当发生依赖冲突时,maven使用“最近者获取策略”(nearest wins strategy),也就是最终会选择依赖树中离工程最近的那个版本。本例中,会选择1.0版本。
maven-dependency.png
假设E的2.0版本中,新增了sayWorld功能,并且在A中,使用到了sayWorld功能,那么就会引起NoSuchMethodError、ClassNotFoundException等问题。

解决依赖冲突

1,可选依赖
A依赖B,B依赖C,如果B中标记C为optional,那么A不依赖C。比如:

<dependency>
    <groupId>cn.timd</groupId>
    <artifactId>ProjectC</artifactId>
    <version>1.0-SNAPSHOT</version>
    <scope>compile</scope>
    <optional>true</optional>
</dependency>

比如在上面的例子中,可以在B中将E标记位optional,来保证A依赖2.0版本的E

2,排除依赖
A依赖B,B依赖C,可以在A中声明对B的依赖的时候,同时排除(由B引入的)对C的依赖。比如:

<dependency>
    <groupId>cn.timd</groupId>
    <artifactId>ProjectB</artifactId>
    <version>1.0-SNAPSHOT</version>

    <exclusions>
        <exclusion>
            <groupId>cn.timd</groupId>
            <artifactId>ProjectC</artifactId>
        </exclusion>
    </exclusions>
</dependency>

比如在上面的例子中,可以在A中声明对B的依赖的时候,排除由B引入的对E 1.0的依赖,来保证A依赖2.0版本的E

3,直接修改项目依赖
上面的例子中,E 2.0之所以没被maven选择,是因为它离A比较远,那么可以直接把E 2.0加入到A的dependencies中,来解决依赖冲突的问题。