三种classpath:

  • 编译项目主代码的时候用的一套classpath
  • 测试
  • 实际运行

项目的依赖根据选择的依赖范围将依赖引入到不同的classpath中

几种依赖范围:

  • compile:编译依赖范围,如果没有指定,就会默认使用这个范围,,对编译、测试、运行三种classpath都有效
  • test:测试依赖范围,只对测试的classpath有效
  • provided:已提供依赖范围,编译和测试有效,运行无效
  • runtime:运行时依赖范围,测试和运行有效
  • system:系统依赖范围,与classpath的关系与provided完全一致,但是使用此依赖时必须通过systemPath元素显示的指定依赖文件的路径。此范围不通过maven仓库解析,与本机系统绑定,可能造成构建的不可移植,systemPath元素可以引用环境变量,如:
dependency>
    <groupId>javax.sql</groupId>
    <artifactId>jdbc-stdext</artifactId>
    <version>2.0</version>
    <scope>system</scope>
    <systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
  • import

传递性依赖:

 A依赖B,B依赖C,C就是A的传递性依赖,Maven会自动解析这些依赖关系。

上述AB的依赖范围是complie(第一依赖),BC的依赖范围是complile(第二依赖),那么AB的依赖范围就是compile,依赖范围与传递性依赖的关系如下表,左边第一列表示第一依赖,最上边一行表示第二依赖。

依赖范围与传递性依赖的关系
  complie test provided runtime
complile complie     runtime
test test     test
provided provided   provided provided
runtime runtime     runtime

 

 

 

 

 

 

规律:第二依赖为complile,传递性依赖与第一依赖一致,第二依赖为test不传递,第二依赖为provided,只传递第一依赖为provided的依赖,第二依赖为runtime,传递性依赖与第一依赖保持一致,compile除外。

依赖调解:

如果项目A有这样的依赖关系:A->B->C->Y(1.0),A->D->Y(2.0),那么A使用Y的哪个版本呢?

第一种调解方式:短路径优先,也就是会使用Y(2.0)

第二种调解方式:如果路径长度相同,会使用先声明的依赖

可选依赖:

假设有这种依赖关系:A->B,B->X(可选),B->Y(可选),也就是说B可以依赖X,也可以依赖Y,比如XY是两种不同的数据库驱动:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.10</version>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>8.4-701.jdbc3</version>
    <optional>true</optional>
</dependency>

那么XY就是B的可选依赖,XY也不会传递,所以项目A如果需要数据库驱动依赖,需要显示声明。

但在理想情况下,不应该使用可选依赖,根据单一职责原则,一个类应该专注一项功能,所以最好将B封装成两个依赖,一个mysql版本,一个pgsql版本。

版权声明:本文为sifeblog原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/sifeblog/p/12031774.html