- 本章主要内容
- maven web 依赖示例(maven1)
- 约定配置
- pom 文件
- maven 坐标
- dependencies依赖导入
- 创建一个maven项目(maven2)
- maven 依赖范围(scope)
- 依赖的传递
- maven依赖调解功能
- 可选依赖(optional元素)
- 排除依赖
原文:
本章主要内容
- maven web 依赖示例
- maven 约定配置
- maven 中 pom 文件
- maven 坐标详解
- maven 依赖导入功能
- maven 依赖范围详解
- maven 依赖的传递
- maven 中依赖调解功能
- 可选依赖(optional 元素)的使用
- 排除依赖的使用
maven web 依赖示例(maven1)
在介绍本章知识点之前,先简单感受一下 maven 的作用。
使用 idea 创建一个 maven 项目,或者前往 https://start.spring.io | https://start.aliyun.io 下载一个 maven 项目,我们只为项目添加 Web 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
以阿里云 [https://start.aliyun.io] 为例:
填好信息之后点击下载,解压压缩包并使用 idea 打开:
新增一个 Controoler 类:
package com.theboyaply.maven1.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author theboyaply
* @version V1.0
* @Date 2020-4-23
* @description
*/
@RestController
public class HelloWorld {
@GetMapping("/hello")
public String sayHello() {
return "Hello World";
}
}
然后在项目根目录下打开 cmd 使用 mvn spring-boot:run
命令启动程序:
D:\myResource\maven\maven1>mvn spring-boot:run
如果本地仓库没有相关 jar 包,会先去远程仓库下载,下载完成后会继续启动程序:
D:\myResource\maven\maven1>mvn spring-boot:run
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< com.theboyaply:maven1 >------------------------
[INFO] Building maven1 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) > test-compile @ maven1 >>>
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven1 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven1 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to D:\myResource\maven\maven1\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven1 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory D:\myResource\maven\maven1\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ maven1 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to D:\myResource\maven\maven1\target\test-classes
[INFO]
[INFO] <<< spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) < test-compile @ maven1 <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) @ maven1 ---
Downloading from nexus-aliyun: http://maven.aliyun.com/nexus/content/groups/public/org/springframework/boot/spring-boot-loader-tools/2.2.6.RELEASE/spring-boot-
loader-tools-2.2.6.RELEASE.pom
Downloaded from nexus-aliyun: http://maven.aliyun.com/nexus/content/groups/public/org/springframework/boot/spring-boot-loader-tools/2.2.6.RELEASE/spring-boot-l
oader-tools-2.2.6.RELEASE.pom (0 B at 0 B/s)
Downloading from nexus-aliyun: http://maven.aliyun.com/nexus/content/groups/public/org/apache/commons/commons-compress/1.19/commons-compress-1.19.pom
Downloaded from nexus-aliyun: http://maven.aliyun.com/nexus/content/groups/public/org/apache/commons/commons-compress/1.19/commons-compress-1.19.pom (0 B at 0
B/s)
Downloading from nexus-aliyun: http://maven.aliyun.com/nexus/content/groups/public/org/apache/maven/maven-archiver/3.4.0/maven-archiver-3.4.0.pom
......
......
下面这个是启动相关的信息:
D:\myResource\maven\maven1>mvn spring-boot:run
[INFO] Scanning for projects...
[WARNING]
[WARNING] Some problems were encountered while building the effective model for com.theboyaply:maven1:jar:0.0.1-SNAPSHOT
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-compiler-plugin is missing. @ line 51, column 12
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]
[INFO]
[INFO] -----------------------< com.theboyaply:maven1 >------------------------
[INFO] Building maven1 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) > test-compile @ maven1 >>>
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven1 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven1 ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven1 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory D:\myResource\maven\maven1\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ maven1 ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] <<< spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) < test-compile @ maven1 <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:2.2.6.RELEASE:run (default-cli) @ maven1 ---
[INFO] Attaching agents: []
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.6.RELEASE)
2020-04-23 10:59:17.233 INFO 21004 --- [ main] com.theboyaply.maven1.Maven1Application : Starting Maven1Application on DESKTOP-LR4IQHF with PID 210
04 (D:\myResource\maven\maven1\target\classes started by theAplyBoy in D:\myResource\maven\maven1)
2020-04-23 10:59:17.237 INFO 21004 --- [ main] com.theboyaply.maven1.Maven1Application : No active profile set, falling back to default profiles: d
efault
2020-04-23 10:59:18.411 INFO 21004 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-04-23 10:59:18.420 INFO 21004 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-04-23 10:59:18.420 INFO 21004 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.33]
2020-04-23 10:59:18.509 INFO 21004 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-04-23 10:59:18.509 INFO 21004 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 12
12 ms
2020-04-23 10:59:18.659 INFO 21004 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-23 10:59:18.788 INFO 21004 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '
'
2020-04-23 10:59:18.791 INFO 21004 --- [ main] com.theboyaply.maven1.Maven1Application : Started Maven1Application in 1.992 seconds (JVM running fo
r 2.777)
可以从启动信息中发现,程序在 8080
端口上启动了(默认为 8080 端口),我们访问 /hello
接口:
http://localhost:8080/hello
效果如下:
可以看见,使用 mvn 之后我们并不需要手动去寻找相关 jar 包添加进项目,而是使用 mvn 依赖的方式进行 jar 管理。mvn 项目管理依赖最重要的一个文件是 pom.xml
,我们这个示例中的 pom.xml
文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.theboyaply</groupId>
<artifactId>maven1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>maven1</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.6.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
上面的 pom.xml 是自动生成的,作用是将 springmvc 所有需要的包都自动导入了,并且还为我们提供了支持 mvn spring-boot:run
启动的功能。
通过 pom.xml 来进行配置,maven 会读取 pom.xml 中的配置信息,来加载我们项目中需要依赖的 jar 包,还有需要如何构件项目等等信息,都可以在 pom 文件中进行配置。
约定配置
maven 提倡使用一个共同的标准目录结构,maven 使用约定优于配置的原则,大家尽可能的遵守这样的目录结构,如下所示:
目录 | 备注 |
---|---|
$ | 存放 pom.xml 和所有的子目录,即项目根目录 |
$/src/main/java | 项目的 java 源码 |
$/src/main/resources | 项目的资源,比如说 property 文件,spring.xml |
$/src/test/java | 项目的测试类,比如说 junit 代码 |
$/src/test/resources | 测试用的资源 |
$/src/main/webapp/WEB-INF | web 应用文件目录,web 项目的信息,比如存放 web.xml、本地图片、jsp 视图页面 |
$/target | 打包输出目录 |
$/target/class | 编译输出目录 |
$/target/test-classes | 测试编译输出目录 |
Test.java | maven 只会自动运行符合该命名规则的测试类 |
~/.m2/repository | maven 默认的本地仓库目录位置 |
结合表格中的约定信息,我们再去看看上面创建的 maven 项目,发现其目录结构与表格中约定的基本一致。
这是 maven 项目标准的结构,大家都按照这个约定来,然后 maven 中打包、运行、部署时候就非常方便了。
pom 文件
当我们在项目中需要用到maven帮我们解决jar包依赖问题,帮我们解决项目中的编译、测试、打包、部署时,项目中必须要有pom.xml文件,这些都是依靠pom的配置来完成的。
POM( Project Object Model,项目对象模型 ) 是 Maven 工程的基本工作单元,是一个XML文件,包含了项目的基本信息,用于描述项目如何构件,声明项目依赖,等等。
执行任务或目标时,Maven 会在当前目录中查找 POM。它读取 POM,获取所需的配置信息,然后执行目标。
POM 中可以指定以下配置:
- 项目依赖
- 插件
- 执行目标
- 项目构件 profile
- 项目版本
- 项目开发者列表
- 相关邮件列表信息
在创建 POM 之前,我们首先需要描述项目组 (groupId),项目的唯一ID。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 模型版本 -->
<modelVersion>4.0.0</modelVersion>
<!-- 定义当前构件所属的组,通常与域名反向一一对应 -->
<groupId>com.theboyaply</groupId>
<!--项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的-->
<artifactId>maven1</artifactId>
<!-- 版本号 -->
<version>0.0.1-SNAPSHOT</version>
</project>
maven 坐标
maven中引入了坐标的概念,每个构件都有唯一的坐标,我们使用maven创建一个项目需要标注其坐标信息,而项目中用到其他的一些构件,也需要知道这些构件的坐标信息。
maven中构件坐标是通过一些元素定义的,他们是groupId、artifactId、version、packaging、classifier,如我们刚刚上面创建的springboot项目,它的pom中坐标信息如下:
<groupId>com.theboyaply</groupId>
<artifactId>maven1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
- goupId:定义当前构件所属的组,通常与域名反向一一对应。
- artifactId:项目组中构件的编号。
- version:当前构件的版本号,每个构件可能会发布多个版本,通过版本号来区分不同版本的构件。
- package:定义该构件的打包方式,比如我们需要把项目打成jar包,采用
java -jar
去运行这个jar包,那这个值为jar;若当前是一个web项目,需要打成war包部署到tomcat中,那这个值就是war,可选(jar、war、ear、pom、maven-plugin),比较常用的是jar、war、pom,这些后面会详解。
上面这些元素中,groupId、artifactId、version是必须要定义的,packeage可以省略,默认为jar。
我们可以将上面创建的springboot项目发布出去,然后只需要告诉别人maven1这个项目的坐标信息,其他人就可以直接使用了,而且其他人用的时候,不用关心maven1运行需要依赖什么,maven1依赖的这些都会自动导入,非常方便。
dependencies依赖导入
maven可以帮我们引入需要依赖的构件(jar等),而maven是如何定位到某个构件的呢?
项目中如果需要使用第三方的jar,我们需要知道其坐标信息,然后将这些信息放入pom.xml文件中的dependencies
元素中:
<project>
<dependencies>
<!-- 在这里添加你的依赖 -->
<dependency>
<groupId></groupId>
<artifactId></artifactId>
<version></version>
<type></type>
<scope></scope>
<optional></optional>
<exclusions>
<exclusion></exclusion>
<exclusion></exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
- dependencies元素中可以包含多个
dependency
,每个dependency
就表示当前项目需要依赖的一个构件的信息 - dependency中groupId、artifactId、version是定位一个构件必须要提供的信息,所以这几个是必须的
- type:依赖的类型,表示所要依赖的构件的类型,对应于被依赖的构件的packaging。大部分情况下,该元素不被声明,默认值为jar,表示被依赖的构件是一个jar包。
- scope:依赖的范围,后面详解
- option:标记依赖是否可选,后面详解
- exclusions:用来排除传递性的依赖
通常情况下我们依赖的都是一些jar包,所以大多数情况下,只需要提供groupId、artifactId、version
信息就可以了。
创建一个maven项目(maven2)
这次我们使用idea来创建。
打开idea,点击File->New->Project
,选择Maven
,如下:
点击Next
,输入项目的maven坐标信息,如下:
点击Next
,输入项目所在目录,如下:
然后点击 Finish
完成项目的创建,项目结构如下:
打开pom.xml,引入springmvc依赖,如下:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
pom.xml文件最终如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.theboyaply</groupId>
<artifactId>maven2</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
</dependencies>
</project>
我们只引入了一个spring-web的jar包,springmvc还需要spring-core等jar包的支持,我们来看一下,maven是否帮我们也导入了。
pom.xml文件中,右键选中Show Dependencies
,可以显示当前项目依赖的jar包,如下:
上图中显示了项目中的依赖信息,箭头有多级,从下至上,第一个箭头表示第一级,是直接依赖,后面的都是间接依赖,属于传递性依赖。
我们在maven2
中添加了spring-web
的依赖,并没有引入spring-beans、spring-core、spring-jcl
的依赖,但是maven都自动帮我们导入了,这是因为spring-web
的pom.xml中定义了它自己的依赖,当我们使用spring-web
的时候,spring-web需要依赖的jar也会自动被依赖进来。
maven 依赖范围(scope)
我们的需求:
- 我们在开发项目的过程中,可能需要用junit来写一些测试用例,此时需要引入junit的jar包,但是当我们项目部署在线上运行了,测试代码不会再执行了,此时junit.jar是不需要了,所以junit.jar只是在编译测试代码,运行测试用例的时候用到,而上线之后用不到了,所以部署环境中是不需要的
- 我们开发了一个web项目,在项目中用到了servlet相关的jar包,但是部署的时候,我们将其部署在tomcat中,而tomcat中自带了servlet的jar包,那么我们的需求是开发、编译、单元测试的过程中需要这些jar,上线之后,servlet相关的jar由web容器提供,也就是说打包的时候,不需要将servlet相关的jar打入war包了
- 像jdbc的驱动,只有在运行的时候才需要,编译的时候是不需要的
这些需求怎么实现呢?
我们都知道,java中编译代码、运行代码都需要用到classpath变量,classpath用来列出当前项目需要依赖的jar包,这块不清楚的可以去看一下classpath和jar。
classpath和jar关系详解:https://www.theboyaply.cn/archives/classpath-and-jar
maven用到classpath的地方有:编译源码、编译测试代码、运行测试代码、运行项目,这几个步骤都需要用到classpath。
如上面的需求,编译、测试、运行
需要的classpath对应的值可能是不一样的,这个maven中的scope为我们提供了支持,可以帮我们解决这方面的问题,scope是用来控制被依赖的构件与classpath的关系(编译、打包、运行所用到的classpath),scope有以下几种值:
compile
编译依赖范围,如果没有指定,默认使用该依赖范围,对于编译源码、编译测试代码、测试、运行4种classpath都有效,比如上面的spring-web。
test
测试依赖范围,使用此依赖范围的maven依赖,只对编译测试、运行测试的classpath有效,在编译主代码、运行项目时无法使用此类依赖。比如junit,它只有在编译测试代码及运行测试的时候才需要。
provided
已提供依赖范围。表示项目的运行环境中已经提供了所需要的构件,对于此依赖范围的maven依赖,对于编译源码、编译测试、运行测试中classpath有效,但在运行时无效。比如上面说到的servlet-api,这个在编译和测试的时候需要用到,但是在运行的时候,web容器已经提供了,就不需要maven帮忙引入了。
runtime
运行时依赖范围,使用此依赖范围的maven依赖,对于编译测试、运行测试和运行项目的classpath有效,但在编译主代码时无效,比如jdbc驱动实现,运行的时候才需要具体的jdbc驱动实现。
system
系统依赖范围,该依赖与3中classpath的关系,和provided依赖范围完全一致。但是,使用system范围的依赖时必须通过systemPath元素显示第指定依赖文件的路径。这种依赖直接依赖于本地路径中的构件,可能每个开发者机器中构件的路径不一致,所以如果使用这种写法,你的机器中可能没有问题,别人的机器中就会有问题,所以建议谨慎使用。
如下:
<dependency>
<groupId>com.theboyaply</groupId>
<artifactId>rt</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
import
这个比较特殊,后面的文章中单独讲,springboot和springcloud中用到的比较多。
scope与classpath的关系
依赖范围 | 编译源码 | 编译测试代码 | 运行测试 | 运行项目 | 示例 |
---|---|---|---|---|---|
compile | Y | Y | Y | Y | spring-web |
test | - | Y | Y | - | junit |
provided | Y | Y | Y | - | servlet-api |
runtime | - | Y | Y | Y | jdbc驱动 |
system | Y | Y | Y | - | 本地的jar包 |
scope如果对于运行范围有效,意思是指依赖的jar包会被打包到项目的运行包中,最后运行的时候会被添加到classpath中运行。如果scope对于运行项目无效,那么项目打包的时候,这些依赖不会被打包到运行包中。
依赖的传递
上面我们创建的maven-chat02
中依赖了spring-web,而我们只引入了spring-web
依赖,而spring-web又依赖了spring-beans、spring-core、spring-jcl
,这3个依赖也被自动加进来了,这种叫做依赖的传递。
不过上面我们说的scope元素的值会对这种传递依赖会有影响。
假设A依赖于B,B依赖于C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,而A对于C是传递性依赖,而第一直接依赖的scope和第二直接依赖的scope决定了传递依赖的范围,即决定了A对于C的scope的值。
下面我们用表格来列一下这种依赖的效果,表格最左边一列表示第一直接依赖(即A->B的scope的值),而表格中的第一行表示第二直接依赖(即B->C的scope的值),行列交叉的值显示的是A对于C最后产生的依赖效果。
compile | test | provided | runtime | |
---|---|---|---|---|
compile | compile | - | - | runtime |
test | test | - | - | test |
provided | provided | - | provided | provided |
runtime | runtime | - | - | runtime |
解释一下:
- 比如A->B的scope是
compile
,而B->C的scope是test
,那么按照上面表格中,对应第2行第3列的值-
,那么A对于C是没有依赖的,A对C的依赖没有从B->C传递过来,所以A中是无法使用C的 - 比如A->B的scope是
compile
,而B->C的scope是runtime
,那么按照上面表格中,对应第2行第5列的值为runtime
,那么A对于C是的依赖范围是runtime
,表示A只有在运行的时候C才会被添加到A的classpath中,即对A进行运行打包的时候,C会被打包到A的包中 - 大家仔细看一下,上面的表格是有规律的,当B->C依赖是compile的时候(表中第2列),那么A->C的依赖范围和A->B的sope是一样的;当B->C的依赖是test时(表中第3列),那么B->C的依赖无法传递给A;当B->C的依赖是provided(表第4列),只传递A->C的scope为provided的情况,其他情况B->C的依赖无法传递给A;当B->C的依赖是runtime(表第5列),那么C按照B->C的scope传递给A
- 上面表格大家多看几遍,理解理解
maven依赖调解功能
现实中可能存在这样的情况,A->B->C->Y(1.0),A->D->Y(2.0),此时Y出现了2个版本,1.0和2.0,此时maven会选择Y的哪个版本?
解决这种问题,maven有2个原则:路径最近原则、最先声明原则
。
路径最近原则
上面A->B->C->Y(1.0),A->D->Y(2.0)
,Y的2.0版本距离A更近一些,所以maven会选择2.0。
但是如果出现了路径是一样的,如:A->B->Y(1.0),A->D->Y(2.0)
,此时maven又如何选择呢?
最先声明原则
如果出现了路径一样的,此时会看A的pom.xml中所依赖的B、D在dependencies
中的位置,谁的声明在最前面,就以谁的为主,比如A->B
在前面,那么最后Y会选择1.0版本。
可选依赖(optional元素)
有这么一种情况:
A->B中scope:compile
B->C中scope:compile
按照上面介绍的依赖传递性,C会传递给A,被A依赖。
假如B不想让C被A自动依赖,可以怎么做呢?
dependency元素下面有个optional,是一个boolean值,表示是一个可选依赖
,B->C时将这个值置为true,那么C不会被A自动引入。
排除依赖
A项目的pom.xml中
<dependency>
<groupId>com.theboyaply</groupId>
<artifactId>B</artifactId>
<version>1.0</version>
</dependency>
B项目1.0版本的pom.xml中
<dependency>
<groupId>com.theboyaply</groupId>
<artifactId>C</artifactId>
<version>1.0</version>
</dependency>
上面A->B的1.0版本,B->C的1.0版本,而scope都是默认的compile,根据前面讲的依赖传递性,C会传递给A,会被A自动依赖,但是C此时有个更新的版本2.0,A想使用2.0的版本,此时A的pom.xml中可以这么写:
<dependency>
<groupId>com.theboyaply</groupId>
<artifactId>B</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>com.theboyaply</groupId>
<artifactId>C</artifactId>
</exclusion>
</exclusions>
</dependency>
上面使用使用exclusions元素排除了B->C依赖的传递,也就是B->C不会被传递到A中。
exclusions中可以有多个exclusion
元素,可以排除一个或者多个依赖的传递,声明exclusion时只需要写上groupId、artifactId就可以了,version可以省略。
-- end --