🤪扫盲 <dependencyManagement>、<dependencies>、spring-boot-starter-parent 及 starter.

576 阅读5分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」。

⭐本文带你扫盲以下 Spring Boot 知识点:

  • <dependencyManagement>
  • <dependencies>
  • <artifactId>spring-boot-starter-parent</artifactId>
  • <artifactId>spring-boot-starter</artifactId>

1. <dependencyManagement> 应用场景

当我们的项目模块很多的时候,我们使用 Maven 管理项目非常方便,帮助我们管理构建、文档、报告、依赖、scms、发布、分发的方法。可以方便的编译代码、进行依赖管理、管理二进制库等等。

由于我们的模块很多,所以我们又抽象了一层,抽出一个 project-parent 来管理子项目的公共的依赖。为了项目的正确运行,必须让所有的子项目使用依赖项的统一版本,必须确保应用的各个项目的依赖项和版本一致,才能保证测试的和发布的是相同的结果。

⭐在我们项目顶层的 pom.xml 文件中,我们会看到 <dependencyManagement> 元素。通过它来管理 jar 包的版本,让子项目中引用一个依赖而不用显示的列出版本号。Maven 会沿着父子层次向上走,直到找到一个拥有 <dependencyManagement> 元素的项目,然后它就会使用在这个 <dependencyManagement> 元素中指定的版本号。

🤔使用 <dependencyManagement> 的好处:

  • 统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,才能保证测试的和发布的是相同的成果,因此,在顶层 pom.xml 中定义共同的依赖关系可以避免在每个使用的子项目中都声明一个版本号,这样想升级或者切换到另一个版本时,只需要在父类容器里更新,不需要任何一个子项目的修改
  • 如果某个子项目需要另外一个版本号时,只需要在各自模块的 <dependencies> 中声明一个版本号即可。子项目就会使用子项目声明的版本号,不继承于父项目版本号。

2. <dependencies>

相对于 <dependencyManagement>,所有声明在 <dependencies> 里的依赖都会自动引入,并默认被所有的子项目继承

3. <dependencyManagement> & <dependencies> 区别

<dependencies> 即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(全部继承)

<dependencyManagement> 里只是声明依赖,并不实现引入,因此子项目需要显式的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且 <version><scope> 都读取自父项目的 pom.xml 文件。另外如果子项目中指定了版本号,那么会使用子项目中指定的 jar 版本。

4. 理解 Spring Boot 项目中的 <parent>

pom.xml 坐标文件中经常见到如下一段引用:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.8.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

对于这个 <parent> 的作用,你是否完全理解?有小伙伴说,不就是依赖的版本号定义在 <parent> 里边吗?是的,没错,但是 <parent> 的作用不仅仅这么简单!

4.1 基本功能

当我们创建一个 Spring Boot 工程时,可以继承自一个 spring-boot-starter-parent ,也可以不继承自它,我们先来看第一种情况。先来看 parent 的基本功能有哪些?

  1. 定义了 Java 编译版本为 1.8
  2. 使用 UTF-8 格式编码
  3. 继承自 spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本号
  4. 执行打包操作的配置
  5. 自动化的资源过滤
  6. 自动化的插件配置
  7. 针对 application.propertiesapplication.yml 的资源过滤,包括通过 profile 定义的不同环境的配置文件,例如 application-dev.propertiesapplication-dev.yml

注意:由于 application.propertiesapplication.yml 文件接受 Spring 样式占位符 $ {...} ,因此 Maven 过滤更改为使用 @ .. @ 占位符,当然开发者可以通过设置名为 resource.delimiter 的 Maven 属性来覆盖 @ .. @ 占位符。

4.2 源码分析

我们可以再本地 Maven 仓库中看到具体的 <parent> 文件,以 2.1.8 版本为例,打开 D:\Software\Maven\.m2\repository\org\springframework\boot\spring-boot-starter-parent\2.1.8.RELEASE\spring-boot-starter-parent-2.1.8.RELEASE.pom 文件 (个人本地 Maven 仓库路径),打开这个文件,快速浏览下文件源码,基本上就可以证实我们前面所说的功能:

我们可以看到,它继承自 spring-boot-dependencies,这里保存了基本的依赖信息,另外我们也可以看到项目的编码格式,JDK 的版本等信息,当然也有我们前面提到的数据过滤信息。最后,我们再根据它的 <parent> 中指定的 spring-boot-dependencies 位置,来看看 spring-boot-dependencies 中的定义:

在这里,我们看到了版本的定义以及 <dependencyManagement> 节点,明白了为什么 Spring Boot 项目中部分依赖不需要写版本号了。

4.3 不使用 <parent>

🔥但是并非所有的公司都需要这个 <parent>,有的时候,公司里边会有自己定义的 <parent>,我们的 Spring Boot 项目要继承自公司内部的 <parent>,这个时候该怎么办呢?

⭐一个简单的办法就是我们自行定义 <dependencyManagement>,然后在里边定义好版本号,再接下来在引用依赖时也就不用写版本号了,像下面这样:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.8.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

这样写之后,依赖的版本号问题虽然解决了,但是关于打包的插件、编译的 JDK 版本、文件的编码格式等等这些配置,在没有使用 <parent> 的时候,这些统统要自己去配置

5. spring-boot-starter

其实 spring-boot-starter 无异于其他的 starter 启动器,只是看上去比较特殊而已:

spring-boot-starter 中所有的依赖项:

Diagram

看过以上图解后,想必已经对 spring-boot-starter 有一个清晰的认识了。

希望本文对你有所帮助🧠
欢迎在评论区留下你的看法🌊,我们一起讨论与分享🔥