前言
dependencyManagement和pluginManagement如何使用以及什么意思?我想懂点Maven的应该都明白,无非是依赖和插件的管理(版本),一般多用于Maven项目的继承和聚合模式中。
这里不是讲解dependencyManagement和pluginManagement的,而是针对这两个元素,记录一个本人发现的问题,理解了这个问题,就可以更有助于依赖和插件的管理。
测试项目,Maven + jdk1.8 + springboot2.6.7
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/>
</parent>
这里我的测试项目结构是
父pom文件中继承了spring-boot-starter-parent,子模块version-test继承了父pom文件,各自主要pom如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/>
</parent>
<groupId>test.version.maven</groupId>
<artifactId>maven-test</artifactId>
<version>1.0-SNAPSHOT</version>
<name>maven-test</name>
<packaging>pom</packaging>
<modules>
<module>version-test</module>
</modules>
<parent>
<groupId>test.version.maven</groupId>
<artifactId>maven-test</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>version-test</artifactId>
<version>1.0-SNAPSHOT</version>
<name>version-test</name>
dependencyManagement
首先在version-test的pom文件中添加junit的依赖(不写version),此时父pom中没有junit的依赖
项目打包mvn clean install,结果是通过的;这很简单,因为父pom中继承了spring-boot-starter-parent,里面配置了junit依赖以及版本,所以version-test直接继承了下来,具体如下
现在继续修改一下,父pom中添加junit的依赖,但是不写version
再次打包,结果就报错了,为什么呢?因为version-test的依赖junit没写version,就会去父pom中查询,父pom中虽然定义了junit的依赖,但没有定义version,这时候就会报错了,这时候可能有人会有疑问,不是父pom继承了spring-boot-starter-parent吗?是的,虽然是这样,但我们父pom中的junit是定义在dependencyManagement中的,它不会再去自己的父pom中找version了,所以就报错了,报错如下
当然,你也可以在父pom中的junit追加上version,这样就可以了,不过,既然继承了spring-boot-starter-parent,里面有的我们最好直接使用,不推荐自己再次定义一个一样的依赖,如果需要的依赖只是版本不同,是可以自己定义的。(定义在父pom中还是定义在子模块中视当前情况而定)
总结
自己项目中维护的dependencyManagement
- 如果使用继承了spring-boot-starter-parent,人家已经定义的依赖,除非你想使用不同的version,否则子模块直接使用即可,不需要重复定义。
- spring-boot-starter-parent中没有的依赖,也就是第三方的依赖,如果定义在dependencyManagement中,需要写明version,否在子模块继承使用的时候不指定version会报错。
- 父pom中在dependencyManagement中定义了依赖,子模块也定义了相同的并追加了version,子模块的会覆盖父的。
pluginManagement
其实pluginManagement和dependencyManagement的作用是一样的,但也存在特殊的地方。
依然是上面的项目结构。
我们经常在使用mvn clean install的时候,需要跳过测试环节,所以我们这样执行Maven命令:mvn clean install -Dmaven.test.skip=true
这样是可以的,也有的时候,我们想要直接在父pom中直接全局定义插件执行的时候跳过测试,命令行就可以不追加参数-Dmaven.test.skip=true了,怎么做呢?(关于Maven插件,生命周期和阶段以及它们之间的绑定关系执行顺序等,这里不多解释了,可以看一下《Maven实战》),我们只需要在父pom中添加如下
pluginManagement中配置了插件maven-surefire-plugin插件的参数skip为true,这时候,我们还需要在子模块引用吗?答案是不要的!!!而且这里我们也没有写version!!!!
可能有些人说,父pom不是继承了spring-boot-starter-parent嘛,肯定里面也定义了插件的版本号,是的,没错,是这样的,但是!!!如果我注释掉了spring-boot-starter-parent呢?
注意!因为刚才我们在上面dependencyManagement的演示中牵扯到了junit的测试,这里注释掉了spring-boot-starter-parent,junit找不到依赖的version了,所以我们先删除掉junit的依赖。
此时再次执行mvn clean install
竟然没有报错,跟dependencyManagement不一样啊?
结果不仅配置的插件生效了,而且也成功了,为什么呢?
注意看!这里的插件mven-surefire-plugin的版本号用的是2.12.4,先记住,我们继续往下看。
现在!放开刚才注释的spring-boot-starter-parent,再次打包测试
也成功了,等等!!!你注意到了嘛?此时插件maven-surefire-plugin的版本号是2.22.2!!!!!
直接说结果和原因吧,这时候插件版本号是继承的spring-boot-starter-parent中的。那么刚才注释掉了spring-boot-starter-parent,为什么还生效呢?原因就是这里
这里面默认定义了jar类型的Maven的生命周期阶段和插件的绑定,插件默认了版本号
看到了嘛,插件版本号是2.12.4,跟刚才注释掉spring-boot-starter-parent的时候一样,对比一下其他插件你会发现版本号是一致的。
回到刚才的问题
- 为什么pluginManagement中的插件maven-surefire-plugin不写版本号不报错呢?因为默认找spring-boot-starter-parent的,没有spring-boot-starter-parent就会使用Maven自己定义好的。
- 为什么子模块不引用插件,就生效呢?不像是dependencyManagement那样必须在子模块定义了才可以使用?因为Maven的官方插件,有一些默认绑定好了,你可以像是依赖那样理解它已经存在了,版本也有了,所以父pom中定义不定义,自己都会生效,只不过父pom中定义了参数或版本呢,子的也会继承下来而已;但是如果pluginManagement中定义的是第三方的插件,不写version是会报错的,而且子模块中也必须像dependencyManagement那样定义引用才可以
总结
这篇博客其实需要你具有Maven生命周期方面的知识才能理解彻底,如果不明白的话,还是建议先搞明白生命周期。