什么是依赖
每个Maven管理的项目,都会有一个唯一的坐标,当项目被打包成一个组件(即Jar包)部署到远程仓库后,其他项目可以通过这个坐标来引入这个组件,在项目中使用。作为动词,依赖指的是这种引用关系;作为名词,依赖指的是被引入的组件。
//比如项目一般都会引入junit组件,我们可以说项目依赖junit,或者说项目要引入junit依赖。
<project>
...
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
...
</project>
传递依赖
项目中引入的依赖,一般也会依赖其他组件库,我们称这些组件库称为传递依赖。
Maven会自动帮我们引入这些传递依赖,不需要开发者显示指定。
自动引入传递依赖的问题
- 循环依赖
- 依赖库会急剧增加,空间占用随之增加
Maven提供以下功能特性避免这两个问题
- 依赖协调
- 依赖管理
- 依赖范围
- 依赖排除
- 依赖可选
依赖协调
顾名思义,项目依赖链中,存在两个版本不同的依赖,这时需要协调使用哪个版本的依赖。
深度不同,短路径优先
D 1.0 会被使用
A
├── B
│ └── C
│ └── D 2.0
└── E
└── D 1.0
深度相同,先定义优先
D 2.0 会被使用
A
├── B
│ └── D 2.0
└── E
└── D 1.0
依赖范围
首先对classpath(简称cp)做一下分类
- 编译cp:源代码开发所处的环境
- 测试cp:开发单元测试所处的环境
- 运行cp:程序编译打包之后运行的环境
依赖范围的作用有两个
- 用于控制依赖的传递性
- 控制一个依赖有效的cp环境
Maven支持6个依赖范围:compile、provided、runtime、test、system、import。(其中system已经废弃)
compile
如果依赖没有指定scope,默认是compile。
- 有效的cp环境:所有
provided
- 有效的cp环境:编译cp、测试cp
- 比如:Servlet API、lombok
runtime
- 有效的cp环境:测试cp、运行cp
test
- 有效的cp环境:测试cp
- 比如:junit
import
只在<dependencyManagement>中类型为<packaging>pom</packaging>的依赖声明中使用,用来做版本管理控制依赖版本的,并不引入传递依赖。
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
...
对传递依赖引入的影响
除了import,其他的范围对于传递依赖自动引入的行为都有不同的影响。
| 范围 | compile | provided | runtime | test |
|---|---|---|---|---|
| compile | compile | - | runtime | - |
| provided | provided | - | provided | - |
| runtime | runtime | - | runtime | - |
| test | test | - | test | - |
说明:比如当前项目引入了scope=compile的依赖A,依赖A又引入scope=runtime的依赖B,那么依赖B会被自动引入,scope=runtime。其他关系类比。
依赖管理
集中统一管理依赖版本,如下例子
<project>
...
<dependencyManagement>
<dependencies>
...
<dependency>
<groupId>group-a</groupId>
<artifactId>artifact-a</artifactId>
<version>1.0</version>
</dependency>
...
</dependencies>
</dependencyManagement>
...
</project>
依赖排除
显示排除传递依赖,如下例子
A -> B -\-> C
<project>
...
<dependencies>
<dependency>
<groupId>group-b</groupId>
<artifactId>B</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>group-c</groupId>
<artifactId>C</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
...
</project>
依赖可选
声明当前依赖可选,自动引入传递依赖时会被忽略。如下,项目A只会引入B依赖。
A -> B -> C(optional)
<project>
...
<dependencies>
<dependency>
<groupId>group-c</groupId>
<artifactId>C</artifactId>
<version>1.0</version>
<optional>true</optional>
</dependency>
</dependencies>
...
</project>