依赖管理
依赖版本提取
当我们有多个包需要版本一致时,就可以使用依赖版本统一提取的方式,在 <properties>
中提取,在 <dependency>
中通过 ${}
统一使用。
<properties>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 名称可以自定义,这样可以统一管理 spring 相关的包版本 -->
<spring.version>6.2.3</spring.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
依赖范围
配置文件 <dependency>
中,可以通过设置坐标的依赖范围(scope
),从而实现对 jar包依赖范围的限制:编译环境、测试环境、运行环境。
依赖范围 | 描述 |
---|---|
compile | 编译范围依赖,<scope> 标签的默认值。在编译、测试、运行三种环境下,都会被使用。如 log4j 在三种环境下都会有效。 |
test | 测试依赖范围,只在测试环境中有效。如 Junit 依赖只在测试阶段有效。 |
provided | 已提供依赖范围,只在编译环境和测试环境中有效,在运行环境中无效。如 servlet-api 依赖只是编译和测试会用到,在运行阶段,服务器会提供环境。 |
runtime | 运行时依赖范围,只对测试环境和运行环境有效。如 JDBC 驱动实现依赖,在其编译时只需 JDK提供的JDBC接口即可。 |
system | 系统依赖范围,其效果与 provided 的依赖范围一致。其用于添加非 Maven 仓库的本地依赖,通过依赖元素 dependency 中的 systemPath 元素指定本地依赖的路径。鉴于使用其会导致项目的可移植性降低,一般不推荐使用。 |
import | 导入依赖范围,该依赖范围只能与 dependencyManagement 元素配合使用,其功能是将目标 pom.xml 文件中 dependencyManagement 的配置导入合并到当前的 pom.xml 中。 |
<dependencies>
<!-- 编译环境、测试环境、运行环境都会用到 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
<scope>compile</scope>
</dependency>
<!-- 只在开发阶段用到(只能在test文件夹下的测试类中使用) -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.4</version>
<scope>test</scope>
</dependency>
<!-- 编译环境、测试环境可以使用,但是不会被打包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
依赖传递
假如有 Maven 的三个项目,项目C 依赖于 项目B,项目B 依赖于 项目A。此时在项目A中配置的包,在项目C中也是可以正常使用的,这就叫做传递依赖。

传递依赖原则
在 C --> B --> A 的依赖关系下,A能够把包传递到C,取决于A中包的依赖范围以及配置:
若 A 中包的依赖范围是 compile 范围,可以传递;
若 A 中包的依赖范围是 test / provided 范围,则不能传递;
若 A 中配置了
<optional>
标签为 true,则不能传递:xml<dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> <!-- 依赖中止 --> <optional>true</optional> </dependency> </dependencies>
出现依赖冲突时,则不能传递;
依赖冲突
当直接引用或者间接引用出现了相同的 jar 包时,一个项目就会出现相同的重复包,这就是依赖冲突。
Maven内部是会自动解决依赖冲突的问题的,同时我们也可以手动解决冲突,但是不推荐。
路径优先原则
路径优先原则是第一原则,即 当前项目距离哪个包的路径最近,Maven就默认使用哪个包。
A --> B --> C --> D --> E --> X(version 1.0)
// 路径较短,优先使用
A --> F --> X(version 2.0)
先声明优先原则
先声明优先原则是第二原则,当 两个项目的路径相同时,就看 dependencies
中,哪个项目靠前就用哪个项目的包。
// 在 dependencies 中先声明谁,就使用谁的包
A --> E --> X(version 1.0)
A --> F --> X(version 2.0)
<!-- maven_B 和 maven_C 中都使用了相同的包,则此时遵循先声明原则,使用 maven_B 的包-->
<dependencies>
<dependency>
<groupId>com.geomind.maven</groupId>
<artifactId>maven_B</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.geomind.maven</groupId>
<artifactId>maven_C</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
提示
配置上面的情况,IDEA右侧的Maven面板中,如果看到 maven_B 和 maven_C下的包都变灰色了,这是IDEA的问题,将配置剪切了重新写入一次就好了。
正常情况下,Maven使用了 maven_B 中的包,则 maven_B 中的包会被高亮显示,而 maven_C下的包会变为灰色。
手动排除依赖
手动排除依赖是最后原则,通过 <exclusion>
标签进行手动排除,来确定当前项目到底引用哪个项目的包。
<dependencies>
<dependency>
<groupId>com.geomind.maven</groupId>
<artifactId>maven_B</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 手动排除 maven_B,使用 maven_C 中的包 -->
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<!-- 手动排除时,不需要写 version 标签 -->
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.geomind.maven</groupId>
<artifactId>maven_C</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
依赖下载失败
在使用 Maven 构建项目时,可能会发生依赖项下载错误的情况,主要原因有以下几种:
- 下载依赖时出现网络故障或仓库服务器宕机等原因,导致无法连接至 Maven 仓库,从而无法下载依赖;
- 依赖项的 groupId、artifactId、version 必须要一一对应,不要想当然的只修改版本号,从而导致依赖性 GAV 不符;
- 本地 Maven 仓库或缓存被污染,导致 Maven 无法继续正确的使用现有的依赖;
解决方案:
- 下载依赖时,检查网络连接和 Maven仓库服务器状态;
- 确保依赖项的 GVA 保持一一对应,建议使用 Mvn Repository 仓库查询并复制;
- 清理本地 Maven 仓库缓存(特指仓库中以 lastUpdated 结尾的文件),只要有 lastUpdated缓存文件,即使刷新也不会重新下载;
扩展:快速清理lastUpdated缓存文件的脚本
@echo off
set REPOSITORY_PATH=您的maven-repository地址
rem 正在搜索...
for /f "delims=" %%i in ('dir /b /s "%REPOSITORY_PATH%\*lastUpdated*"') do (
del /s /q %%i
)
rem 搜索完毕
pause