Maven-依赖机制

366 阅读1分钟

什么是依赖

每个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:程序编译打包之后运行的环境

依赖范围的作用有两个

  1. 用于控制依赖的传递性
  2. 控制一个依赖有效的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,其他的范围对于传递依赖自动引入的行为都有不同的影响。

范围compileprovidedruntimetest
compilecompile-runtime-
providedprovided-provided-
runtimeruntime-runtime-
testtest-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>