maven 依赖管理最佳实践

2022-06-27 12:34:33 浏览数 (1)

1. 概述

maven 是一个常用的 java 跨平台项目管理工具,主要工作是项目构建、依赖管理和项目信息管理。 除了编写源代码,我们每天有相当一部分时间花在了编译、运行单元测试、生成文档、打包和部署等繁琐而不起眼的工作上,这就是项目的构建过程。 而 maven 可以自动地从清理、编译、测试到生成报告、打包、部署,极大的简化了我们日常的工作,同时它还是一个依赖管理工具和项目信息管理工具,提供了中央仓库,能帮助我们自动下载构件。 作为 java 程序员必备的工具,深入研究和了解 maven 的使用是非常重要的,尤其是在构建失败、包冲突解决时,只有了解了我们即将介绍的 maven 工具的用法和要点才不会一筹莫展。 本文我们就来重点介绍一下 maven 作为依赖管理和项目信息管理工具的使用。

2. maven 依赖的声明

maven 最强大的功能就是项目中依赖的管理。 根元素 project 下的 dependencies 可以包含一个或多个 dependency 元素,以声明一个或者多个项目依赖。

代码语言:javascript复制
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${spring.version}</version>
    <scope>test</scope>
</dependency>

如上所示,maven 依赖由以下几个元素构成:

元素

是否必须

备注

groupId、artifactId、version

maven 依赖的基本坐标

tpye

依赖的类型,默认为 jar

scope

依赖的范围

optional

标记依赖是否可选

exclusions

排除传递性依赖选项

3. scope — 依赖范围

maven 在不同的阶段,使用的包加载路径是不同的。

  • 编译项目主代码时使用 compile classpath
  • 编译和执行测试时使用 test classpath
  • 在实际运行Maven项目时使用 runtime classpath

依赖范围就是用来控制依赖于这三种 classpath 的关系的,maven 有以下几种依赖范围可供选择:

  • compile — 编译依赖范围,如果没有指定,默认使用该依赖范围
  • test — 测试依赖范围,使用此依赖范围的 maven 依赖,只对 test classpath 有效
  • provided — 已提供依赖范围,使用此依赖范围的 maven 依赖,对于 compile 和 test classpath 有效,但在运行时无效
  • runtime — 运行时依赖范围,使用此依赖范围的 maven 依赖,对于 test 和 runtime classpath 有效,但在编译主代码时无效
  • system — 系统依赖范围,其与三种 classpath 的关系,和 provided 依赖范围一致

依赖范围Scope

对于compile classpath有效

对于test classpath有效

对于runtime classpath有效

例子

compile

Y

Y

Y

spring-core

test

&nbsp;

Y

&nbsp;

JUnit

provided

Y

Y

&nbsp;

servlet-api

runtime

&nbsp;

Y

Y

JDBC 驱动实现

system

Y

Y

&nbsp;

本地的 maven 仓库之类的类库文件

3.1. 依赖范围的传递性

如果 A 依赖 B,B 依赖 C,那么 C 对于 A 就是传递性依赖。 下表列出了依赖范围的传递性:

第一依赖

compile

test

provided

runtime

第二依赖

compile

compile

/

/

runtime

test

test

/

/

test

provided

provided

/

provided

provided

runtime

runtime

/

/

runtime

4. 依赖仲裁

maven 依赖仲裁(Dependency Mediation)遵循以下两个原则: 1. 最短路径优先原则 2. 第一声明优先原则,在依赖路径长度相等的前提下,在POM中依赖声明最靠前的依赖优先

例如,项目A有这样的依赖关系: 1. A -> B -> C -> X(1.0),A -> D -> X(2.0),X(1.0) 路径长度为 3,X(2.0) 路径长度为 2,根据第一原则,X(2.0) 会被解析使用; 2. A -> B -> Y(1.0),A -> C -> Y(2.0),Y(1.0) 和 Y(2.0) 的依赖路径长度相同,如果 B 的依赖声明在C之前,那么 Y(1.0) 会被解析使用。

5. 依赖相关的命令

  • mvn dependency:list — 列出最终确定的依赖
  • mvn dependency:tree — 打出依赖树
  • mvn dependency:analyze — 依赖分析,给出项目中已使用但未声明的依赖,以及未使用但已声明的依赖

6. POM 优化

6.1. 依赖管理

  • 多模块项目中,定义一个主 pom,在主 pom 中使用 dependencyManagement 定义依赖、版本和依赖排除
  • 子模块从主 pom 中继承依赖,一般情况下,不要在子模块中做依赖排除,也不要指定依赖版本

6.2. 归类依赖

如果多个相关的依赖的版本都是相同的,可以使用 properties 元素定义 maven 属性,依赖的版本值用这一属性引用表示。

代码语言:javascript复制
<properties>
    <spring.version>2.5.6</spring.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>

7. 参考资料

Maven实战(Maven in Action) Maven权威指南。 Maven重要概念及最佳实践 — https://segmentfault.com/a/1190000000640821。 Maven依赖范围及传递 — https://blog.csdn.net/stypace/article/details/38440545

0 人点赞