maven依赖·介绍
三种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版本。