DLancerC

Maven 学习笔记(二)

Maven Dependency,Maven 除了快速构建项目外,还有一大功能就是管理项目依赖。Maven 的依赖管理通过groupId、artifactId、version等标识确定一个依赖的坐标,从而通过 Maven 仓库或获取对应的项目依赖的 Jar,自动化的解析任何一个 Java 构件。

Maven 坐标

  • groupId:
    定义当前Maven项目隶属的实际项目.

  • artifactId:
    定义实际项目中的一个Maven项目(模块).

  • version:
    定义maven项目当前所处的版本.

  • packaging:
    定义Maven项目的打包方式.

  • classifier:
    定义构建输出的一些附属构件. 例如:一个项目的主构件是xxx-xxx-7.0.0.jar, 可能还需要javadoc和source, 这时javadoc和source就是附属构件的classifier, classifier不能定义, 它不是默认生成的, 而是由附加插件帮助生成的.
    groupId, artifactId, version是必须的, packaging 是可选的(默认jar), 而classifier是不能自定义的.

    maven项目生成的文件名一般为 artifactId-version[-classifier].packaging

依赖 POM 定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<project>
...
<!-- 项目所有的依赖-->
<dependencies>
<!-- 定义一个模块使用的一个依赖-->
<dependency>
<!-- 依赖的基本坐标-->
<groupId></groupId>
<artifactId><artifactId>
<version></version>
<!-- 依赖类型,对应项目目标定义中的packaging, 不声明默认为Jar -->
<type></type>
<!-- 依赖作用范围-->
<scope></scope>
<!-- 标记依赖是否可选-->
<optional></optional>
<!-- 需要排除的依赖 -->
<exclusions>
<exclusion></exclusion>
</exclusions>
</dependency>
</dependencies>
...
</project>

依赖范围Scope

Maven会使用3种classpath来控制使用的依赖(编译classpath, 测试classpath, 运行测试classpath).Maven有以下几种依赖范围.

  • compile
    编译依赖范围. 默认依赖范围, 对应编译, 测试, 运行三种classpath都有效. eg: Spring-core
  • test
    测试依赖范围. 只对测试classpath有效, 在编译主代码或者运行项目中无法使用该依赖. eg: JUint
  • provided
    已提供的依赖范围. 对于编译和测试时有效, 运行时无效使用. eg: servlet-api
  • runtime
    运行时依赖范围. 对应测试和运行时有效, 但项目编译时无效. eg: JDBC ,编译时使用JDK提供的JDBC接口.
  • system
    系统依赖范围. 依赖范围和provided完全一致, 但是需要显示的指定依赖文件路径. 此类不是由Maven仓库解析处理,往往与本机系统绑定

    1
    2
    3
    4
    5
    6
    7
    <dependency>
    <groupId></groupId>
    <artifactId><artifactId>
    <version></version>
    <scope>system</scope>
    <systemPath>${java.home}/lib/rt.jar</systemPath>
    </dependency>
  • import
    导入依赖范围. 该依赖不会对classpath产生实际影响.

Scope compile classpath test classpath runtime classpath
compile Y Y Y
test - Y -
provided - Y Y
runtime - Y Y
system Y Y -

依赖传递

依赖传递
依赖范围不但可以控制3种classpath的依赖,对传递性依赖也会产生影响.

compile test provided runtime
compile compile - - runtime
test test - - test
provided provided - provided provided
runtime runtime - - runtime

eg:
Honks Test (Scope:Test, 对应表中行,第一依赖) 依赖Spring-email(Scope:compile, 对应表中列,第二依赖), Spring-email依赖java-mail. 则Honks Test通过传递依赖java-mail

依赖调解

  • 依赖路径最近者优先
  • 依赖路径相同, 先声明的优先

eg:

  • A -> B -> C -> X(1.0), A -> B -> X(2.0), 优先使用 X(2.0) [路径更短]
  • A -> B -> X(1.0), A -> B -> X(2.0), 优先使用 X(1.0) [先声明]

依赖定义优化

  • 定义优化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <project>
    <modleVersion>4.0.0</modleVersion>
    <groupId>com.dlc.maven</groupId>
    <artifactId>maven</artifactId>
    <version>1.0.0</version>
    <!-- 依赖归类 -->
    <properties>
    <springframework.version>3.6</springframework.version>
    </properties>
    <dependencies>
    <dependency>
    <!-- 使用依赖归类 -->
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${springframework.version}</version>
    <groupId>org.springframework</groupId>
    <artifactId>maven-dep</artifactId>
    <version>${springframework.version}</version>
    <groupId>com.dlc.maven</groupId>
    <artifactId>maven-dep</artifactId>
    <version>1.0.0</version>
    <!-- 依赖排除 -->
    <exclusions>
    <exclusion>
    <groupId>com.dlc.maven</groupId>
    <artifactId>maven-dep-dep</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    </dependencies>
    </project>
  • 依赖优化

    1
    2
    3
    4
    5
    6
    7
    8
    # 查看当前项目的已解析依赖
    mvn dependency:list
    # 查看当前项目的依赖树
    mvn dependency:tree
    # 分析当前项目依赖
    mvn dependency:analyze
    # 输出 Used undeclared dependencies, 项目中使用的但没有显式声明的依赖(但当前项目依赖的传递性依赖中存在)
    # 输出 Unused declared dependencies, 项目未使用的, 当显式声明的依赖