0%

Maven-4-依赖管理

基本概念

前面我们已经写了两个简单的Maven项目,其中HelloFridend Maven项目就是依赖于Hello项目。Maven的项目依赖关系分为直接依赖和间接依赖,假设我们有这样一个问题背景有A、B、C三个Maven项目,其中A依赖于B,并且B依赖于C,那么其中的依赖关系如下。

  1. 直接依赖:A->BB->C
  2. 间接依赖:A->C

依赖的范围

根据依赖的范围大小分为compile(默认)、test、provided、runtime、import、system等

其中最常用的是:compile、test、provided,并且只有范围为compile的依赖可以被其他Maven工程访问。

为了演示这个效果,首先我们创建两个Maven工程AB

然后在B中引入A的依赖。

pom文件如下所示:

pom(A).xml

pom(B).xml

image-20230630144916417

然后然AB项目重新加载Maven工程,当我们不指定依赖范围时:

image-20230630145052895

image-20230630145105550

可以看到在B的依赖关系中,不仅依赖于A还可以继承了A中的junit

接下来我们将A中的junit依赖关系设置为test,然后重新加载ABMaven工程。

pom(A).xml

image-20230630145321349

pom(B).xml

image-20230630145340114

工程A的依赖。

image-20230630145501268

工程B的依赖。

image-20230630145538313

可以看到这个时候在B中只有A的依赖,junit依赖不见了,这个就是test与默认的compile的区别。

依赖冲突问题

前面的内容我们解决了依赖的传递范围问题,但是还有可能出现以下两种矛盾的情况:

  1. A依赖BB还依赖C,这个时候如果BC中存在同名的依赖该如何处理,A中的依赖是谁的。
  2. A依赖BA还依赖C,这个时候如果BC中存在同名的依赖该如何处理,A中的依赖是谁的。

解决上述问题我们有一个口诀:路径最短者优先,路径相同时先声明者优先。

接下来创建实际的Maven项目进行测试。为了演示效果我们再创建一个名为CMaven工程。

最短路径者优先

首先在C中引入依赖junit 4.9并且设置依赖范围为compile,然后在B中引入C的依赖和junit 4.13的依赖,接下来在A中引入B的依赖。

pom(C).xml

image-20230630150839420

pom(B).xml

image-20230630151025194

pom(A).xml

image-20230630151115337

接下来重载所有的Maven工程。

image-20230630151150871

然后查看每个工程的依赖情况如下:

image-20230630151303396

image-20230630151322095

image-20230630151339022

可以看到A中最终获取到的junit版本为4.13,是从工程B中获取得到。

路径相同时先声明者优先

这个时候同样在C中引入依赖junit 4.9并且设置依赖范围为compile,然后在B中引入junit 4.13的依赖并且设置依赖范围为compile,接下来在A中同时引入BC的依赖。

pom(C).xml

image-20230630151716650

pom(B).xml

image-20230630151740766

pom(A).xml

image-20230630151755652

这个时候再次重新加载所有Maven工程,并查看所有工程的依赖关系如下。

image-20230630151925962

image-20230630151936051

image-20230630151946894

这个时候可以看到在工程A中的junit版本为4.9说明A获取到的junit是从C中拿到的,因为我们在导入依赖时先声明的是工程C

依赖的排除

前面的我们使得工程A依赖工程C,此时如果工程C中有junit并且可见性是compile这个时候工程A也会获取到C中对应的junit。有的时候我们只想依赖工程A但是不想获取工程C中的某个依赖,在无法修改其可见性时(例如:调用MySQL驱动包时想不获取其内部的某个子依赖),该如何操作?这个时候就需要使用到,依赖排除技术。

使用方式,在<dependency></dependency>内引用<exclusions></exclusions>标签。

演示效果如下:

  • pom(A).xml

image-20230702231825682

  • pom(C).xml

image-20230702231907222

重新加载工程A和工程C,查看其依赖情况。

image-20230702232036278

此时,在工程A中就无法获取到工程C中的junit依赖。

统一管理目标Jar包的版本

以对Springjar包依赖为例:Spring的每一个版本中都包含spring-contextspringmvcjar包。我们应该导入版本一致的Spring jar包,而不是使用4.0.0spring-context的同时使用4.1.1springmvc

比如现在xml如下所示,在使用相关依赖时,需要保证所有的依赖版本一致,例如此处都为4.0.0.RELEASE,一共有4个依赖,如果我们需要修改Spring的版本就需要同时修改所有的依赖版,如果是一个个的去改肯定不是我们写代码的思想,我们应该会想可不可以去定义一个变量,然后统一定义所有的版本号,这在.xml文件中也是有这样的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>

可以使用<properties></properties>标签实现操作,然后在需要引用的地方使用${}形式进行引用。

如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<properties>
<spring.version>4.0.0.RELEASE</spring.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>

这样依赖,进行版本调整时只需要改一个地方即可。

以工程C进行演示,修改配置文件后,重新加载工程C

image-20230702234236520

可以看到,所有的版本全部都被修改为了4.0.0.RELEASE

-------------本文结束感谢您的阅读-------------