Maven配置之dependencyManagement

今天小林子突然发来一条消息:

小林子:这个关键字是干嘛用的,为什么我的子模块导入不了依赖的jar?是子模块需要配置什么吗?

image-20210107214458024

串一串:这是gradle吧,dependencyManagement的作用是什么你知道么?

小林子:…

串一串:看来你是不知道哈,在单模块中,我们使用dependencies就可以实现对依赖的引入和管理,并且模块中使用的依赖版本会和我们手动引入的依赖版本一致,版本冲突的可能性较低(但有冲突的可能),这种是我们常用的管理依赖的办法。

小林子:懂了

串一串:懂个屁了懂了,这只是说了单模块,多模块的依赖如何管理你也懂了吗?

小林子:…那多模块的依赖应该怎么搞呢?是不是在父pom.xml中使用dependencies进行引入就可以了?

串一串:如果在父模块中直接使用dependencies的话,就会把父模块中引入的依赖全部导入到所有的子模块中,这就会出现一个问题:父模块中依赖了starter-redis.jar,子A模块需要用到starter-redis.jar,而子B模块中用不到该jar包,所以就没有在B的配置文件中配置Redis的相关信息,那么这时启动B模块,就会报错。

串一串:你看看你的配置文件,除了dependencies和imports之外,还有什么?是不是还有dependencyManagement,这个东西就是出现在父pom.xml中的,当然也可以出现在单模块中,比如我们使用spring-cloudspring-cloud-alibaba的时候。dependencyManagement不会导入依赖,只是声明一个依赖(声明的范围包括groupId、artifactId、version、type、scope、classifier等),意思也就是如果在子模块中只需要指定依赖的groupId和artifactId即可,如果该依赖在父或本pom中的dependencyManagement中有声明,则该依赖的其他信息自动继承,无需再次声明version、type、scope等信息。

小林子:有点懵…

串一串:给你看一段代码,你解读一下,目录结构是这样的:

image-20210108223101327
  • 父模块pom.xml
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
30
31
32
33
34
35
36
37
38
39
40
41
42
> <?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>
> <parent>
> <groupId>org.springframework.boot</groupId>
> <artifactId>spring-boot-starter-parent</artifactId>
> <version>2.2.6.RELEASE</version>
> <relativePath/>
> </parent>
> <groupId>cc.kevinlu</groupId>
> <artifactId>maven-demo</artifactId>
> <version>1.0.0-SNAPSHOT</version>
> <packaging>pom</packaging>
>
> <properties>
> <java.version>1.8</java.version>
> <fastjson.version>1.2.61</fastjson.version>
> </properties>
>
> <dependencyManagement>
> <dependencies>
> <dependency>
> <groupId>org.projectlombok</groupId>
> <artifactId>lombok</artifactId>
> <version>1.18.12</version>
> </dependency>
> <dependency>
> <groupId>com.alibaba</groupId>
> <artifactId>fastjson</artifactId>
> <version>${fastjson.version}</version>
> </dependency>
> <dependency>
> <groupId>mysql</groupId>
> <artifactId>mysql-connector-java</artifactId>
> <version>5.1.46</version>
> </dependency>
> </dependencies>
> </dependencyManagement>
>
> </project>
>
  • 子模块pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
> <?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>
> <parent>
> <!-- 引入parent依赖 -->
> <groupId>cc.kevinlu</groupId>
> <artifactId>maven-demo</artifactId>
> <version>1.0.0-SNAPSHOT</version>
> </parent>
> <groupId>cc.kevinlu</groupId>
> <artifactId>module-one</artifactId>
>
> <dependencies>
> <dependency>
> <groupId>org.springframework.boot</groupId>
> <artifactId>spring-boot-starter-web</artifactId>
> </dependency>
> </dependencies>
> </project>
>
>

我们在父pom.xml中的dependencyManagement声明了三个依赖jar包,分别是lombok、fastjson、mysql-connector-java,并指定了相关依赖的版本号,,而在子pom.xml中,只引入了spring-boot-starter-web一个依赖,现在我们看一下module-one的所有依赖项:

image-20210110004053248

发现在子模块module-one中并没有导入其父模块中dependencyManagement声明的jar包。那么如果我们这个时候想要在module-one中引入fastjson,该怎么做呢?

小林子:那还不简单么,直接在dependencies中加一个dependency就好了啊,就这样:

1
2
3
4
5
6
> <dependency>
> <groupId>com.alibaba</groupId>
> <artifactId>fastjson</artifactId>
> <version>1.2.61</version>
> </dependency>
>

串一串:嗯,不算太笨嘛,但是你有没有想过,如果在这里不指定fastjson的version的话,该依赖的版本会是多少?

小林子:呃。。。会报错吧,好像是Dependency not found错误吧

串一串:你试一试吧

—A Few Moments Later—

串一串:怎么样,和你刚才说的结果一样吗?

小林子:为什么我删掉了module-one中的version还是能引入1.2.61版本的jar,是缓存的原因吗?

串一串:可能是缓存的原因吧,哈哈~但是即使你reimport之后,它的版本依然还是1.2.61,你看看父pom.xml的dependencyManagement中对fastjson的声明的版本是多少,然后你把里面的版本改为1.2.62,reimport后看看模块module-one的fastjson版本有没有变化

小林子:变了,哦~原来是这里的原因,那也就是说我只需要在模块中用dependency指定依赖的groupId和artifactId就可以了,其他的都不需要再重复写了,然后它就会自动的使用父模块或者本模块的dependencyManagement中声明的其他信息,对吧?

串一串:嗯,是的,这样做的目的就是统一管理整个工程的依赖,防止出现因为版本冲突出现的BUG,至于为什么使用这种方法可以实现对依赖的管理,那就要从依赖传递开始说起了,下次再聊这个,再聊一个问题:如果在父pom.xml和子pom.xml都通过dependencyManagement声明了一个依赖的不同版本,那么在子模块中使用该依赖时,对应的版本将会是哪个?

小林子:根据依赖传递的特性,应该是子模块中声明的吧

串一串:嗯,是的,说的很对,如果想要在子项目中使用特定版本的依赖,那么就指定一下version就可以了,例如:

1
2
3
4
5
6
> <dependency>
> <groupId>com.alibaba</groupId>
> <artifactId>fastjson</artifactId>
> <version>1.2.69</version>
> </dependency>
>

这时子模块中引入的fastjson的版本就会是1.2.69,传递依赖的就近原则

串一串:好了,就说这么多吧,下回再讲讲传递依赖。