在开发 spring boot 项目时,你是否遇到过,有些依赖即使不写版本号也能下载到某一版本的依赖。
比如下面这个案例
pom文件
<?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.1.9.RELEASE</version> <relativePath/> </parent> <groupId>com.wqlm</groupId> <artifactId>boot</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 复制代码
可以看到 <dependencies>
下配置了三个依赖项
这个项目虽然引用了三个依赖,但只有 mybatis-spring-boot-starter 这个依赖是写了版本号的,其余两个没写。
我们知道导入一个依赖需要提供 依赖的坐标 (groupId 、 artifactId 、 version)
参考maven 坐标
既然 spring-boot-starter-web 和 mysql-connector-java 没有提供 version ,那么应该无法正确下载依赖才对。
但实际情况如图
spring-boot-starter-web 和 mysql-connector-java都能找到对应都版本,这是为什么。
不知道大家注意到没,该 pom 是有 parent 的
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> <relativePath/> </parent> 复制代码
也就是说该项目继承自 spring-boot-starter-parent 项目。具体继承了那些东西,我们点进去及可以看到了
如下图 spring-boot-starter-parent 又继承自 spring-boot-dependencies
再点进去可以看到 spring-boot-dependencies 的pom文件如下
可以看到 spring-boot-dependencies 没有 parent , 说明它是 顶级pom ,其中 <properties>
内定义了很多版本号, mysql-connector-java 的版本号就在里面
是不是和上面看到的版本号一样,都是8.0.17
下面是 spring-boot-dependencies-2.1.9.RELEASE.pom 中的部分内容
注意以下三个组件
其中 properties 定义了一系列的版本号,并且在 dependencyManagement 中使用了版本号。注意这个 dependencyManagement ,它的下级是我们最常用的 dependencies 组件
我们知道 dependencies 组件是用来引入依赖的,那在外面包上一层 dependencyManagement 是什么意思呢? 它的意思是, 声明 dependencies 中的依赖,但不引用!!! 那什么时候引用呢?当子项目中配置了一个 dependency ,并且这个 dependency 没写版本号,且在 dependencyManagement 中声明过 时才引用。
这就是为什么有的依赖包需要写版本号,有的不需要写。那些不需要写版本号的依赖,其实在它的父pom的 dependencyManagement 中已经申明好了,而且不仅申明了 version ,有的还申明了 exclusions ,用于剔除某些冲突的依赖
上面说了 dependency , plugin 也是同理。不信你回头看案例的pom文件,它里面就定义了一个 spring-boot-maven-plugin 的插件,也没有写版本号。
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> 复制代码
它的版本号同样是在父pom的 pluginManagement 中申明好的
dependencies 组件用于导入依赖,且所有 dependencies 里的依赖都会被子项目继承。
像 spring boot 这种大体量的框架,旗下子项目众多,比如
这些子项目也有各自的依赖,其中有些依赖是公共的,比如
spring-boot-starter-web-2.1.9.RELEASE和 spring-boot-starter-data-redis--2.1.9.RELEASE 的依赖结构如下
他们都依赖了 spring-boot-starter ,既然都是都是 spring-boot 的子项目,并且版本号也一样,那么他们两个依赖的 spring-boot-starter的版本也应该要一样,不然同时引用他们两个就会出现依赖冲突!
如何保证所有子项目的公共依赖的版本一致呢,总不能在每个子项目里写死吧,这样手动去管理得累死。
所以 spring boot 将所有公共依赖抽离出来,放到 spring-boot-dependencies 中来管理。 所有的子项目都直接或间接继承自 spring-boot-dependencies ,这样同一个版本的所有的子项目的公共依赖就都一样了。
但这样做带来了一个问题,每个子项目都继承了所有都公共依赖,解决这件事情,就需要使用 maven 的 depencyManagement 组件
作用: 用来申明依赖,但不导入。
dependencies 组件用于导入依赖,注意两者区别
使用 depencyManagement 组件后,所有的子项目只需要在父pom 的 “公共依赖声明池” 中挑选自己想要的依赖,而不用关心版本。这样即不会继承到不需要的依赖,又统一了依赖的版本
如果想统一调整所有子项目某个依赖的版本,只需要在父pom 里更新。不需要修改任何一个子项目。
如果某个子项目不想使用公共的版本号,只需要在 dependency 中加上版本号,子项目就会使用自定义的版本号,不会继承父类版本号。
spring boot 就是通过这样来统一管理依赖版本的
基于这样的特性, depencyManagement 组件 一般用于统一管理子项目的公共依赖的版本