Maven 依赖的 Scope 元素
原文(简单修改):Maven 依赖中的 Scope 详解
scope 元素的作用:控制 dependency 元素的使用范围。通俗的讲,就是控制 jar 包在哪些范围被加载和使用。
compile(默认)
compile 是默认值,如果没有指定 scope 值,该依赖的 scope 为 compile。被依赖项目需要参与到当前项目的编译,测试,打包,运行等阶段。打包的时候通常会包含被依赖项目。
provided
被依赖项目理论上可以参与编译、测试、运行等阶段,相当于 compile,但是再打包阶段做了 exclude 的动作。
适用场景:例如,如果我们在开发一个 web 应用,在编译时我们需要依赖 servlet-api.jar,但是在运行时我们不需要该 jar 包,因为这个 jar 包已由应用服务器提供,此时我们需要使用 provided 进行范围修饰。再比如,Lombok 的作用是在编译阶段处理编译结果,而在正式编译完成之后,是不需要 Lombok 的,所以 Lombok 的 scope 为 provided。
runtime
表示被依赖项目无需参与项目的编译,但是会参与到项目的测试和运行。与 compile 相比,被依赖项目无需参与项目的编译。
适用场景:例如,在编译的时候我们只需要 JDBC API 的 jar 包,而在运行的时候我们才需要 JDBC 驱动包,所以 MySQL 等数据库供应商提供的驱动包的 scope 为 provided。
test
表示被依赖项目仅仅参与测试相关的工作,包括测试代码的编译,执行。
适用场景:例如,Junit 测试。
system
system 元素与 provided 元素类似,但是被依赖项不会从 maven 仓库中查找,而是从本地系统中获取,systemPath 元素用于制定本地系统中 jar 文件的路径。例如:
<dependency>
<groupId>org.open</groupId>
<artifactId>open-core</artifactId>
<version>1.5</version>
<scope>system</scope>
<systemPath>${basedir}/WebContent/WEB-INF/lib/open-core.jar</systemPath>
</dependency>
import
它只使用在<dependencyManagement>
中,表示从其它的 pom 中导入 dependency 的配置。
在 SpringBoot 项目中,常会看到如下 pom 内容:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
其中spring-boot-dependencies
是用来做依赖版本管理的。这里 import scope 的作用是,把spring-boot-dependencies
中的内容导入到dependencyManagement
中。实际上我们可以自己在dependencyManagement
中做依赖版本管理:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
但是spring-boot-dependencies
已经把 SpringBoot 相关的许多依赖版本管理好了,所以,我们直接导入即可。
scope 的依赖传递
A–>B–>C。当前项目为 A,A 依赖于 B,B 依赖于 C。知道 B 在 A 项目中的 scope,那么怎么知道 C 在 A 中的 scope 呢?答案是:
当 C 是 test 或者 provided 时,C 直接被丢弃,A 不依赖 C;否则 A 依赖 C,C 的 scope 继承于 B 的 scope。
-
test
和provided
的处理:test
:C 只在测试阶段可用,A 在其运行时不需要 C,因此 C 被丢弃。provided
:C 由外部环境提供(例如,容器或应用服务器),A 也不需要 C,因此 C 被丢弃。
-
范围继承:
-
当 C 的范围是
compile
或runtime
时,A 依赖于 C,并且 C 的范围会继承 B 的范围。这意味着:- 如果 B 的范围是
compile
,则 C 的范围也是compile
。 - 如果 B 的范围是
runtime
,则 C 的范围也是runtime
。 - 如果 B 的范围是
test
,则 C 的范围是test
。
- 如果 B 的范围是
-