Maven - 依赖管理(四)

 Maven的依赖管理可以分为以下几个部分:

1. 依赖范围

2. 依赖传递

3. 依赖调解

4. 可选依赖

5. 依赖排除

6. 依赖优化

 

首先,我们看一下在pom中,对依赖管理的配置结构

<dependency>

  <!--坐标-->
  <groupId/>
  <artifactId/>
  <version/>

  <!--附属构件名称,即相同三维坐标下还存在不同的构件时,使用它来区分。比如某构件坐标有:json-lib-2.2.2-jdk13.jar,json-lib-2.2.2-jdk15.jar两个地址,这时使用附属构件名称jdk15来区分-->
  <classifier/>

  <!--依赖范围,有compile,runtime,test,system,provided,缺省compile-->
  <scope/>

  <!--仅对scope范围是system的构件有效,定义该构件在本地文件系统中的绝对路径-->
  <systemPath/>

  <!--排除传递性依赖的构件-->
  <exclusions>
    <exclusion>
      <artifactId/>
      <groupId/>
    </exclusion>
   </exclusions>

   <!--是否为可选依赖(仅在传递性依赖计算时生效),缺省false-->
   <optional/>

</dependency>

 

依赖范围 scope

我们知道Maven在编译,测试,运行时会使用不同的classpath,因为不同资源在不同阶段不一定是必须的。比如 junit ,在编译,测试阶段是需要的,但运行期却不需要;servlet-api.jar 在编译,测试阶段是有效的,但运行期容器(如tomcat)已经提供了。依赖范围就是控制依赖在三种classpath中的行为:

 

1. compile :   编译依赖范围,缺省值。该范围对编译,测试,运行三种classpath都有效。

2. test :         测试依赖范围。只对编译测试代码和运行测试时有效,在编译主代码和运行项目时,是无法使用此类依赖的。

3. provided : 已提供依赖范围。在编译,测试的classpath有效,但运行时无效,如servlet-api。

4. runtime :   运行时依赖范围。对测试classpath有效,但编译主代码时无效。如JDBC驱动实现,在编译阶段只需要使用JDK提供的JDBC接口,只有在运行项目时才会加载。

5. system :    与provided范围一致,但需要指定systemPath。由于依赖本地文件系统,不推荐。



 

依赖传递

在使用依赖时,Maven会使用依赖传递性规则帮助我们下载依赖的依赖。比如声明依赖A, A又依赖于B, B依赖于C,记为 A -> B, B -> C, 此时,A对B称为第一直接依赖,B对C为第二直接依赖,A -> C为传递性依赖。

所以,我们可以在pom中仅声明依赖A,B和C的依赖关系就会相应地加载过来。注意,并不是所有范围的依赖都可以加载的,只有满足下图关系时,依赖才得以传递:

 

左边第一列为第一直接依赖,上方第一行为第二直接依赖,交点为依赖传递性:


从上图可以看出:

1. 当第二直接依赖范围为 compile 时,依赖得以传递。

2. 当第二直接依赖范围为 test 时,依赖无法传递(即依赖包无法加载到项目中)。

3. 当第二直接依赖范围为 provided 时,只有第一直接依赖也是 provided 时才得以传递。

4. 当第二直接依赖范围为 runtime 时,依赖得以传递(除第一直接依赖为 compile 外)。

 

举例来说,假设我们在 pom.xml 中声明依赖A[scope=compile], 其中A又依赖于B[scope=runtime],B又依赖于C,我们称A为第一直接依赖,B为第二直接依赖,则C得以传递,范围为runtime。

 

依赖调解

假设项目有如下的依赖关系:

A -> B -> C -> X(v1.0),A -> D -> X(v2.0)

X是A的传递性依赖,两条路径上X的深度与版本是不一样的。Maven的依赖调解将根据以下规则进行调解,选择合适的X:

1. 最短路径优先

2. 当路径长度一致时,最先声明优先

 

如上例,X(v2.0) 因为路径较短,得到依赖传递关系。

 

可选依赖 optional

假设 A -> B, B -> X(可选), B -> Y(可选),因为X,Y都是可选依赖,所以即使A,B范围都是compile,依赖也不会传递。如果要使X, Y依赖生效,只能显式声明。

 

依赖排除

假设A -> B, B -> C(snapshot),在A项目发布时(snapshot -> release),因为传递依赖C可能是不稳定版本(或某些原因你不想使用C),这时可以通过 exclusions 排除C的依赖传递,而显示声明稳定版本。



 
 

依赖优化

通过Maven处理后的依赖,包括直接依赖与传递依赖,统称为已解析依赖(Resolved Dependency)。

我们可以使用下面的工具分析与优化依赖:

1. mvn dependency:list

2. mvn dependency:tree

3. mvn dependency:analyze

 

参考

http://maven.apache.org/ref/3.3.3/maven-model/maven.html

http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html

Maven实战  - 许晓斌

猜你喜欢

转载自liang-hr.iteye.com/blog/2246423