Maven依赖管理
Maven最小依赖
pom.xml文件最小内容:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 模型版本 -->
<modelVersion>4.0.0</modelVersion>
<!-- 定义当前构件所属的组,通常与域名反向一一对应 -->
<groupId>com.example</groupId>
<!--项目唯一ID,一个groupId下可能有多个项目,靠artifactId来区分-->
<artifactId>maven-demo</artifactId>
<!-- 版本号 -->
<version>1.0-SNAPSHOT</version>
<!--打包方式(jar、war、pom),不配置默认打jar包-->
<packaging>jar</packaging>
</project>
Maven依赖范围
Maven用于项目的构建,它会执行一系列编译、测试和部署运行等操作,在不同的操作下使用的classpath不同,依赖范围就是用来控制依赖与三种 classpath(编译classpath、测试classpath、运行classpath)的关系;
Maven有以下几种依赖范围:
- compile:编译依赖范围(默认),使用此依赖范围对于编译、测试、运行三种classpath 都有效,即在编译、测试和运行的时候都要使用该依赖jar包;
- test:测试依赖范围,只能用于测试classpath,而在编译和运行主程序项目时无法使用此jar包依赖,典型的是JUnit,它只用于编译测试代码和运行测试代码的时候才需要;
- provided: 此依赖范围,对于编译和测试classpath有效,而对运行时无效,典型的是servlet包;
- runtime:运行时依赖范围,对于测试和运行classpath有效,但是在编译主代码时无效,典型的就是JDBC驱动实现;
- system:系统依赖范围,和provided依赖范围一致,使用system范围的依赖时必须通过systemPath元素显示地指定依赖文件的路径,不依赖Maven仓库解析,所以可能会造成建构的不可移植,谨慎使用;jar包存放在项目下或者磁盘。
Maven的依赖范围通过scope标签定义。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<!--依赖范围-->
<scope>test</scope>
</dependency>
Maven依赖传递
当我们在项目中加入spring-web依赖,而spring-web又依赖了spring-beans、spring-core、spring-jcl等,那么这3个依赖也被自动加了进来,这种叫做依赖的传递;
而scope元素的值会对这种传递依赖会有影响,影响结果如下图:
A依赖于B,B依赖于C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,而A对于C是传递性依赖。
上图第一列:即A->B的scope的值
上图第一行:即B->C的scope的值
行列交叉的值显示的是A对于C最后产生的依赖效果。
依赖传递有一定规律:
(1)当B->C依赖是compile的时候(表中第2列),那么A->C的依赖范围和A->B的sope是一样的;
(2)当B->C的依赖是test时(表中第3列),那么B->C的依赖无法传递给A;
(3)当B->C的依赖是provided(表第4列),只传递A->C的scope为provided的情况,其他情况B->C的依赖无法传递给A;
(4)当B->C的依赖是runtime(表第5列),那么C按照B->C的scope传递给A;
Maven依赖调节
依赖调节的两个原则:
(1)路径最近原则。
(2)最先声明原则。
实际开发中可能存在这种情况,A->B->C->X(1.0),A->D->X(2.0),此时X出现了2个版本1.0和2.0,此时A项目会选择X的哪个版本?
解决这种问题,maven有2个原则:
- 路径最近原则
上面A->B->C->X(1.0),A->D->X(2.0),X的2.0版本距离A更近一些,所以A项目会选择2.0;
但如果出现了路径距离一样,如:A->B->X(1.0),A->D->X(2.0),此时maven又如何选择? - 最先声明原则
如果出现了路径一样,此时会看A的pom.xml中所依赖的B、D在dependencies中的位置,谁的声明在最前面,就以谁的为准,比如A->B在前面,那么最后X会选择1.0版本。
Maven可选依赖
比如情况如下:
A->B中scope: compile
B->C中scope: compile
按照上面的依赖传递性,C会传递给A,被A依赖;
如果此时B不想让C被A自动依赖,怎么办?
dependency元素下采用optional选项配置,它是一个boolean值,表示是一个可选依赖,B->C时将这个值置为true,那么C不会被A自动引入;
断开依赖传递性
Maven依赖排除
A->B的1.0版本,B->C的1.0版本,scope都默认为compile,根据依赖传递性,C会传递给A,会被A自动依赖,但C此时有个更新的版本2.0,A想使用2.0的版本,则需要使用依赖排除;
在dependency中使用exclusion进行以来排除。