在Maven中依赖的域有:compile、provided、runtime、system、test、import
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>5.1.46</version>
//可省略不写
<scope>compile</scope>
</dependency>
compile(编译)表示被依赖项目需要参与当前项目的编译,当然后续的测试,运行周期也参与其中,是一个比较强的依赖。打包的时候通常需要包含进去。
当依赖的scope为provided的时候,在编译和测试的时候有效,在执行(mvn package)进行打包时不会加入。
比如, 我们开发一个web应用,在编译时我们需要依赖servlet-api.jar,但是在运行时我们不需要该 jar包,因为这个jar 包已由web服务器提供,如果在打包时又被加入进去,那么就可能产生冲突。此时我们就可以使用 provided 进行范围修饰。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
与provided相同,不过被依赖项不会从maven仓库获取,而是从本地文件系统拿,需要配合systemPath属性使用。比如:
<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>
依赖仅参与运行周期中的使用。一般这种类库都是接口与实现相分离的类库,比如JDBC类库,在编译之时仅依赖相关的接口,在具体的运行之时,才需要具体的mysql、oracle等等数据的驱动程序。 此类的驱动都是为runtime的类库。
与compile相比,跳过编译而已,说实话在终端的项目(非开源,企业内部系统)中,和compile区别不是很大。比较常见的如JSR×××的实现,对应的API jar是compile的,具体实现是runtime的,compile只需要知道接口就足够了。oracle jdbc驱动架包就是一个很好的例子,一般scope为runntime。另外runntime的依赖通常和optional搭配使用,optional为true。我可以用A实现,也可以用B实现。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
<scope>runtime</scope>
</dependency>
当依赖的scope为test的时候,指的的是在测试范围有效,在编译与打包的时候都不会使用这个依赖。相当于在打包阶段做了exclude的动作。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
import依赖范围不会像test、compile、runtime依赖范围,对项目的 依赖产生直接的影响。
它的作用是将其他模块中的 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 ,除了复制、继承之外,还可以编写如下配置,将它们导入进去。
<!-- 使用这种方式更灵活,但需要添加编译插件1.8版本的声明,否则默认为1.5 -->
<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>
<!--
依赖范围import只在dependencyManagement元素下才有效果,使用该范围的依赖通常指向一个pom,作用是将目标pom中的dependencyManagement配置导入并合并到当前pom的dependencyManagement配置。
-->
注意:scope的import 属性只能在dependencyManagement 中使用,并且type的类型是pom,表示将其它的pom文件中dependencyManagement管理的依赖全部复制到当前文件中的dependencyManagement区域中,进行依赖的版本锁定。
此时即使引入文件中的version中使用的是propertise定义的版本变量,也是可以成功引入的。
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。
传递依赖失效示意图:
- | 传递依赖 | complie | provided | runtime | test |
---|---|---|---|---|---|
直接依赖 | - | - | - | - | - |
complie | - | complie | 失效 | runtime | 失效 |
provided | - | provided | provided | provided | 失效 |
runtime | - | runtime | 失效 | runtime | 失效 |
test | - | test | 失效 | test | 失效 |
1、https://www.programminghunter.com/article/5007542247/
2、https://blog.csdn.net/u013912696/article/details/103755236