:::info 注:以下所有的结论基于maven3.6.1版本得出。 :::
Maven中的依赖作用范围概述
Maven中使用 scope
来指定当前包的依赖范围和依赖的传递性。
这个scope就是作用域。
例如:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
那么这个scope作用域到底是什么呢
这个scope就是classpath。
maven使用这个scope依赖范围控制哪些依赖在哪些classpath 中可用,哪些依赖包含在一个应用中。
scope各种取值详解
常见的可选值有:compile, provided, runtime, test, system 等。scope
主要是用在 pom.xml
文件中的依赖定义部分
例如:
scope取值 | 有效范围(compile, runtime, test) | 依赖传递 | 例子 | 备注 |
---|---|---|---|---|
compile(默认) | all | 是 | spring-core | |
provided | compile, test | 否 | servlet-api | |
runtime | runtime, test | 是 | JDBC驱动 | |
test | test | 否 | JUnit | |
system | compile, test | 是 | 配合systemPath使用 |
compile (编译范围)
compile是默认的范围;如果没有提供一个范围,那该依赖的范围就是编译范围。编译范围依赖在所有的classpath 中可用,
同时它们也会被打包。
provided (已提供范围)
provided 依赖只有在当JDK 或者一个容器已提供该依赖之后才使用。
例如, 如果你开发了一个web 应用,你可能在编译classpath 中需要可用的Servlet API 来编译一个servlet,但是你不会想要在打包好的WAR 中包含这个Servlet API;这个Servlet API JAR 由你的应用服务器或者servlet 容器提供。已提供范围的依赖在编译classpath (不是运行时)可用。它们不是传递性的,也不会被打包。
runtime (运行时范围)
runtime 依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如,你可能在编译的时候只需要JDBC API JAR,而只有在运行的时候才需要JDBC驱动实现。
test (测试范围)
test范围依赖 在一般的编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用。
system (系统范围)
system范围依赖与provided 类似,但是你必须显式的提供一个对于本地系统中JAR 文件的路径。这么做是为了允许基于本地对象编译,而这些对象是系统类库的一部分。这样的构件应该是一直可用的,Maven 也不会在仓库中去寻找它。如果你将一个依赖范围设置成系统范围,你必须同时提供一个systemPath
元素。注意该范围是不推荐使用的(你应该一直尽量去从公共或定制的 Maven 仓库中引用依赖)。
import
import 只能在 <dependencyManagement>
标签内使用,import 意思是当此依赖被真正使用时,它的 <scope>
都应该被替换上有效的 scope。
scope的依赖传递
当我有三个依赖,A->B->C,当前项目为A,A依赖于B,B依赖于C。
则:B为A的直接依赖,C为A的传递依赖。
知道B在A项目中的scope,那么怎么知道C在A中的scope呢?
答案是:
当C是test
或者provided
时,C直接被丢弃,A不依赖C;
否则A依赖C,C的scope继承于B的scope。
下面是一张nexus画的图(已测无误)。
:::info
遇到依赖没有传递过来的问题我们通常的解决方案是在本工程中直接添加所需的依赖,而不是修改 scope 作用域,比如修改 junit 的作用域为 compile,这样并不合理,junit 只是测试时候用。
:::
注:依赖传递图与网上很多版本不符的问题
在网上看到了很多其他版本,并且在一本maven书上也看到了这种版本的依赖传递表,如下
这与我看到的资料产生了冲突,心中不免有了疑惑,双方的主要不同在于,当A依赖B和B依赖C的scope取值都是provided的时候,结果不同。
经过自己demo测试得到如下截图
当demo-a依赖demo-b的scope取值为provided,demo-b依赖demo-c的取值也为provided的时候,此时在demo-a中编译期并不能拿到demo-c的依赖,故我认为这种说法可能有一定的误区。