maven中强大的scope标签详解
本文目的
接上一篇maven的版本号version的总结及理解
当我在封装工具jar
包的时候,发现有些依赖,是一定要在工具代码里使用的,比如我做的工具包里使用了spring
的方法,那我在工具项目里就需要引用spring-web
包。
但是因为咱们都是spring
项目,像这个包肯定将来会在子项目里,比如通过引用了spring-boot-starter-web
,自动将spring-web
包也带进去了。那这样就会产生了引用冲突。如下图:
一般这种情况,也不会出什么问题,基本开发工具、编译器,自动会优先引用其中一个。(依赖调解机制,后边会写到这个)
但是作为一个合格的码农,这种事情尽管问题不大,但是凌乱的引用,违背我严谨的初衷。因此本篇的主角scope
就是帮助我们解决这种问题的最佳方法。
正文
1. 什么是scope
比如下图,看下scope
的位置:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
<scope>runtime</scope>
</dependency>
2. scope
的概念
首先,我们一个maven
项目依赖生效其实分为三个时期,编译期
、测试期
、运行期
,即,在编译代码的时候,需要使用一套classpath
;test测试的时候使用另一套依赖classpath
;而到了项目运行时,又需要另一套依赖classpath
。
scope
一般称为依赖范围。通过合理的配置,可以控制当前依赖在不同时期编译期
、测试期
、运行期
生效的关系。
3. scope
的分类
scope
有compile
、test
、provided
、runtime
、system
、import
几种。
- compile : 称为编译依赖范围。如果引用的依赖没有指定scope,默认会使用该依赖范围。使用此依赖范围,表示对于上边说的
编译期
、测试期
、运行期
三种classpath
都有效。 - test:称为测试依赖范围。只对
测试期
classpath有效,典型的是JUnit
依赖,只需要在编译测试代码(src/test)和运行测试的时候才需要。 - provided : 已提供依赖范围。对于
编译期
、测试期
classpath有效。使用该依赖范围,表示当前依赖将来会默认由引用项目一定引用,就不需要多引用了。本文最开始介绍的那种情况,就可以对工具项目中的spring-web
依赖,加上<scope>provided</scope>
标签。 - runtime : 运行时依赖范围。对于
测试期
、运行期
classpath有效。 - system : 系统依赖范围。该依赖和
provided
依赖范围一样,但是在使用该依赖的时候,需要指定systemPath
标签,显示的指定依赖jar
的路径。使用此依赖范围,表示的是从本地磁盘上找依赖,不是从maven
仓库中解析了。使用此依赖的时候要注意,因为是从自己本地磁盘上找依赖,因此如果多个人在共同开发,比较麻烦,还要拷贝那个依赖jar
到对方机器上的相同路径下。因此不建议使用这个依赖范围。 - import : 导入依赖范围。该依赖对于上边说的三种
classpath
期都没有作用。该范围的依赖只在dependencyManagement
标签才有效。它的作用是将目标pom
的dependencyManagement
标签中的依赖,合并到当前pom
的dependencyManagement
标签内,供引用项目中使用。由于import
依赖的特殊性,一般看到import
范围时,就会存在<type>pom</type>
,即指向打包类型为pom
的模块。比如下边这样:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.4.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
4. 传递性依赖
当一个项目引用了mybatis-plus-boot-starter
包时,因为它的pom里配置了mybatis-plus
依赖,并且声明了compile
作用域,因此我引入前者后,同样也会把后者引入到项目中,如下图,这种叫传递性依赖
。我通过idea
看的项目依赖情况:
另外,关于mybatis-plus-boot-starter
的pom
,对于mybatis-plus
的依赖情况如下:
即声明了compile
,因此对于mybatis-plus-boot-starter
来说,因为mybatis-plus
声明了compile
,因此表示它在mybatis-plus-boot-starter
中的编译期
、测试期
、运行期
三种classpath
都有效,而我们项目在引用mybatis-plus-boot-starter
时,同样使用的是compile
。这样就会让我们项目同时拥有了mybatis-plus
。
如果我们修改不同的<scope>
值,会看到不同的依赖效果,具体的效果参照《maven实战》里的下图:
因此,依赖范围scope
,不仅控制依赖于三种classpath
的关系,还对依赖性传递产生影响。
5. scope
的应用场景
说了这么多的scope
范围,一般的开发可能根本不关心,但是如果想更加严谨些,你就需要考虑这些,来保证项目的依赖管理更加规范。
因为每个公司都有架构师,架构师负责对基础框架的升级改造,而他做的东西,将来都要封装成几个依赖Jar包,放到公司私服,将来供引用项目,直接使用。
比如约定项目采用springboot + mybatis-plus + lombok + shiro + druid
,这些不同的版本,都不应该让各个项目自己来引用,都应该架构师来约定好版本,把基础配置做成几个Jar,将这些相关依赖设置成<scope>compile</scope>
(不写默认是compile),这样各个子项目都不需要单独引用这些依赖。
而对于一些个别包,比如引用项目将来会一定引用的,这样做的依赖jar包,就可以设置成<scope>provided</scope>
,比如像最开始说的那个spring-web
包。