JAVA语言之解析Maven依赖机制

110 篇文章 4 订阅
本文详细介绍了Maven的依赖管理,包括依赖的传递性、依赖调解的路径最近者优先和第一声明者优先原则,以及如何通过排除和设置可选依赖来管理冲突。通过mvn dependency指令分析项目依赖,并展示了如何在遇到版本冲突时调整依赖关系,确保正确版本的库被使用。
摘要由CSDN通过智能技术生成

依赖传递

依赖相关命令

mvn dependency:list:查看当前项目所有依赖。
mvn dependency:tree:以树的形式显示当前项目的所有依赖,相比mvn dependency:list 列表显示,能很清楚的看到某个依赖是通过哪条依赖路径引入的。
mvn dependency:analyze:分析项目的依赖关系,并确定哪些依赖是:使用和声明、使用和未声明、未使用和声明。

依赖的传递性

如有依赖关系为A->B->C,A依赖B,称为直接依赖。A本身不依赖C,但C通过B传递给A,称C为A的传递性依赖。

通过mvn dependency:list查看A项目的依赖列表,可以看到依赖B和C:

[INFO] — maven-dependency-plugin:2.8:list (default-cli) @ A —

[INFO] 

[INFO] The following files have been resolved:

[INFO]    com.nocoffee:B:jar:0.0.1-SNAPSHOT:compile

[INFO]    junit:junit:jar:3.8.1:test

[INFO]    com.nocoffee:C:jar:0.0.1-SNAPSHOT:compile

[INFO] 

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS 

[INFO] ------------------------------------------------------------------------

依赖调解

场景1:

路径1:A->B->C(version:1.0)
路径2:A->D->E->C(version:2.0)
通过两条依赖路径可以看出,A的传递性依赖的C有两个不同版本,为了避免依赖重复,最终只能选择一个。这种情况Maven采用路径最近者优先的原则来处理,路径1中C到A的距离比路径2中C到A的距离要短,于是路径1中C(version:1.0)最终被A依赖。

mvn dependency:tree 查看依赖路径:

[INFO] — maven-dependency-plugin:2.8:tree (default-cli) @ A —

[INFO] com.nocoffee:A:jar:0.0.1-SNAPSHOT

[INFO] +- com.nocoffee:B:jar:0.0.1-SNAPSHOT:compile

[INFO] |  \- com.nocoffee:C:jar:0.0.1-SNAPSHOT:compile

[INFO] |     \- com.nocoffee:D:jar:0.0.1-SNAPSHOT:compile

[INFO] |        \- com.nocoffee:E:jar:0.0.1-SNAPSHOT:compile

[INFO] \- junit:junit:jar:3.8.1:test

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

场景2:

路径1:A->B->C(version:1.0)
路径2:A->D->C(version:2.0)
路径1和路径2中C到A的距离是相同的,通过路径最近者优先原则无法判断该使用哪个依赖,此时Maven会使用第一声明者优先原则进行选择,第一声明者优先原则是指在POM依赖中声明顺序最靠前的那个依赖会被选择。在A的POM文件中B的声明靠前,于是C(version:1.0)会被选择。

<dependencies>

<dependency>

  <groupId>com.nocoffee</groupId>

  <artifactId>B</artifactId>

  <version>0.0.1-SNAPSHOT</version>

</dependency>

<dependency>

  <groupId>com.nocoffee</groupId>

  <artifactId>D</artifactId>

  <version>0.0.1-SNAPSHOT</version>

</dependency>

<dependency>

  <groupId>junit</groupId>

  <artifactId>junit</artifactId>

  <version>3.8.1</version>

  <scope>test</scope>

</dependency>

mvn dependency:tree 查看依赖路径:

[INFO] — maven-dependency-plugin:2.8:tree (default-cli) @ A —

[INFO] com.nocoffee:A:jar:0.0.1-SNAPSHOT

[INFO] +- com.nocoffee:B:jar:0.0.1-SNAPSHOT:compile

[INFO] |  \- com.nocoffee:C:jar:0.0.1-SNAPSHOT:compile

[INFO] +- com.nocoffee:D:jar:0.0.1-SNAPSHOT:compile

[INFO] \- junit:junit:jar:3.8.1:test

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

排除依赖

在场景2中,如果要使A依赖C(version:2.0) ,则可以配置排除依赖:

<dependency>

  <groupId>com.nocoffee</groupId>

  <artifactId>B</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <exclusions>

    <!-- 排除依赖 C -->

    <exclusion>

        <groupId>com.nocoffee</groupId>

        <artifactId>C</artifactId>

    </exclusion>

  </exclusions>

</dependency>

<dependency>

  <groupId>com.nocoffee</groupId>

  <artifactId>D</artifactId>

  <version>0.0.1-SNAPSHOT</version>

</dependency>

<dependency>

  <groupId>junit</groupId>

  <artifactId>junit</artifactId>

  <version>3.8.1</version>

  <scope>test</scope>

</dependency>

mvn dependency:tree 查看依赖路径,A不再通过B依赖C,而是通过D依赖C:

[INFO] — maven-dependency-plugin:2.8:tree (default-cli) @ A —

[INFO] com.nocoffee:A:jar:0.0.1-SNAPSHOT

[INFO] +- com.nocoffee:B:jar:0.0.1-SNAPSHOT:compile

[INFO] +- com.nocoffee:D:jar:0.0.1-SNAPSHOT:compile

[INFO] |  \- com.nocoffee:C:jar:0.0.1-SNAPSHOT:compile

[INFO] \- junit:junit:jar:3.8.1:test

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

可选依赖

可以将某个依赖配置为可选依赖,则该依赖不会参与依赖传递。

以场景2为例,可以在B的pom.xml里将C配置为可选依赖,使A依赖D的C(version:2.0)。

<dependency>

  <groupId>com.nocoffee</groupId>

  <artifactId>C</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <!-- 设置可选依赖 -->

  <optional>true</optional>

</dependency>

mvn dependency:tree 查看依赖路径,A不再通过B依赖C,而是通过D依赖C:

[INFO] — maven-dependency-plugin:2.8:tree (default-cli) @ A —

[INFO] com.nocoffee:A:jar:0.0.1-SNAPSHOT

[INFO] +- com.nocoffee:B:jar:0.0.1-SNAPSHOT:compile

[INFO] +- com.nocoffee:D:jar:0.0.1-SNAPSHOT:compile

[INFO] |  \- com.nocoffee:C:jar:0.0.1-SNAPSHOT:compile

[INFO] \- junit:junit:jar:3.8.1:test

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

依赖范围

Maven在编译、测试、运行时都会使用不同的classpath,依赖范围是用来控制依赖和三种classpath的关系。

依赖范围介绍

1.compile:编译依赖范围,默认使用该依赖范围,在所有classpath中都可用,并且依赖项将传播到依赖项目。

2.provided:已提供依赖范围,只对于编译和测试classpath有效,运行时无效,如Servlet API,此范围不具有传递性。

3.runtime:运行时依赖范围,只对于测试和运行classpath有效,但在编译主代码时无效。

4.test:测试依赖范围,只对于测试的classpath有效,仅适用于测试编译和执行阶段,如junit。此范围不具有传递性。

5.system:系统依赖范围,该依赖于三种classpath的关系和provided依赖范围完全一致。区别在于system依赖范围必须通过systemPath元素显示的指定依赖文件的路径。

6.import:导入依赖范围,该依赖范围不会对三种classpath产生影响,只有在部分中的pom类型依赖项才支持此范围,它指示要替换为指定POM的部分中的有效依赖项列表的依赖项。由于它们被替换,具有导入范围的依赖项实际上不参与限制依赖项的传递性。

依赖范围对依赖传递的影响

每个范围(import导入依赖范围除外)以不同方式影响传递依赖性,如下表所示。以A->B->C依赖路径为例,左边第一列为第一直接依赖(B在A中的依赖范围),最上面一行为第二直接依赖(C在B中的依赖范围),交叉单元格为传递性依赖范围(C在A中的依赖范围)。

文章来源:网络 版权归原作者所有

上文内容不用于商业目的,如涉及知识产权问题,请权利人联系小编,我们将立即处理

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值