为什么会有scope标签
- maven在编译项目主代码时需要一套classpath, 但是测试时会使用另外一套classpath, 而实际运行maven项目是,又会使用另外一套classpath,所以,会有scope标签用来标识引入的依赖在那个阶段会被使用到。
- 编译classpath指的是target/classes下目录
- 测试classpath指的是target/test-classes下目录
- 运行classpath指的是jar包中BOOT-INF/classes下目录
- 依赖出传递,比如说A项目需要依赖B项目,但是B项目中有一个依赖是测试时需要的,这时候可以通过scope标签来排除B中无关的依赖传递到A项目中。
依赖范围
compile
编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。典型的例子是spring-core,在编译、测试和运行的时候都需要使用该依赖。test
测试依赖范围。使用此依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此类依赖。典型的例子是JUnit,它只有在编译测试代码及运行测试的时候才需要。provided
已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试class-path有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器已经提供,就不需要Maven重复地引入一遍。runtime
运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行class-path有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。system
系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围的依赖时必须通过systemPath元素显式地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。systemPath元素可以引用环境变量,如:
<dependency>
<groupId>javax.sql</groupId>
<artifactId>jdbc-stdext</artifactId>
<version>2.0</version>
<scope>system</scope>
<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
import(Maven 2.0.9及以上)
导入依赖范围。该依赖范围不会对三种classpath产生实际的影响,它的作用是将其他模块定义好的 dependencyManagement 导入当前 Maven 项目 pom 的 dependencyManagement 中。例如存在一个Maven 工程com.maven.first,它的 pom 中的 dependencyManagement 配置如下:
<project>
...
<groupId>com.maven</groupId>
<artifactId>first</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
...
<dependencyManagement>
<dependencies>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${project.build.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${project.build.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${project.build.spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
...
</project>
而另一个Maven 工程 com.maven.second,需要引用 first 工程的 pom 中定义dependencyManagement ,除了复制、继承之外,还可以编写如下配置,将它们导入进去。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.maven</groupId>
<artifactId>first</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
这样就可以把first的dependencyManagement配置引入到second工程中了。
依赖范围与classpath的关系
传递依赖图谱
左侧第一列为第一依赖,上方第一行为第二依赖。相交点为传递性依赖的取值。
名词解释:A依赖B, 则A对B为第一依赖,B同时依赖C, 则B对C是第二依赖,A对C为传递性依赖。