4_企业级依赖管理深入解读 Maven BOM
企业级依赖管理深入解读 Maven BOM
提出疑问(What)
接触第一次是SpringBoot、Hutool、Spring阿里巴巴Cloud 、现在项目也在用,来看看他的详细
BOM should be declared in dependencyManagement for import
当开发者在一个大型项目中使用 Maven 进行依赖管理时,项目往往会包含多个模块或子项目,并且这些模块会共享相同的依赖项。但是,不同模块可能会独立地指定各自的依赖版本,这可能导致以下问题:
- 依赖版本不一致: 不同模块中对相同依赖项使用不同的版本号,可能导致潜在的兼容性问题或冲突。
- 版本管理困难: 在多个模块中管理和维护依赖版本的一致性可能变得复杂,因为需要手动确保每个模块中的依赖版本保持同步。
- 重复配置: 在每个模块中单独指定依赖项的版本,导致了大量的重复配置,增加了维护成本。
为解决以上问题,Maven BOM(Bill of Materials,依赖关系管理)被引入,提供了一种集中管理依赖版本的方法。
此时可能会有疑问:我可以在项目的根pom中通过<dependencyManagement>
标签来集中化管理项目的所有依赖啊。
诚然,当项目使用 Maven 的 dependencyManagement
标签集中管理依赖时,确实能够集中指定依赖版本,==但这种方式并不能将该项目的依赖版本供其他项目使用==;相信大家对springboot并不陌生,在使用springboot的开发过程中我们通常可以看到如下依赖:
<!--引入Spring Boot官方维护的bom依赖清单-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--引入阿里依赖bom清单-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>aliyun-spring-boot-dependencies</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Spring Boot BOM(Bill of Materials,依赖关系管理)的优势在于,它不仅集中管理依赖版本,还允许其他项目通过引用 Spring Boot BOM 来继承其依赖版本管理的功能。换句话说,其他项目可以直接引入 Spring Boot BOM,继承其所管理的依赖版本,而无需单独指定每个依赖的版本。
什么是BOM
Maven 项目的打包类型时,通常可以分为三种:
- jar: 这是最常见的打包类型,适用于普通的 Java 项目。项目会以 jar 类型的格式进行打包。
- pom: 这种类型的项目通常被用作多模块项目的管理和维护。在父模块中定义了依赖项、插件等内容,实现了对版本的统一维护管理。
- war: 这类项目打包成为可运行的 Java Web 项目,例如可以在诸如 Tomcat、Jetty 等应用服务器上运行。
BOM 实际上是一个以 POM 类型定义的普通 Maven 项目,主要用于维护描述 Maven 项目所需的一系列公共依赖信息。通过引用 BOM 项目,可以实现对依赖版本的统一维护管理,而无需明确指定每个依赖项的版本号。 BOM的文件结构
<parent>
<groupId>org.example</groupId>
<artifactId>maven-bom-examples</artifactId>
<version>${revision}</version>
</parent>
<!--pom类型,多模块中依赖统一管理维护-->
<packaging>pom</packaging>
<artifactId>example-bom</artifactId>
<properties>
<!--统一维护管理变量-->
</properties>
<dependencyManagement>
<dependencies>
<!--统一维护管理的依赖-->
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<!--插件依赖统一管理-->
</plugins>
</pluginManagement>
</build>
使用指南
创建bom
当创建 BOM(Bill Of Materials,物料清单)时,常见的两种方式包括:
单独仓库存放依赖: 在一个专门的仓库中,建立 BOM 模块用于存放特定需求的依赖信息。这种方法适用于需要隔离和管理独立的依赖需求,确保依赖版本独立于其他项目。 应用内创建 BOM 模块: 在现有应用的仓库中创建 BOM 模块,让应用的所有子模块共享使用。这种方法适用于在应用内统
选择使用哪种方式创建 BOM 取决于需求的特点和项目的架构,本文参考aliyun-spring-boot 实现方式,即应用内创建BOM模块。 新建一个maven-bom-examples
项目,其目录结构如下:
maven-bom-examples
├─.idea
├─example-bom
│ └─pom.xml
└─pom.xml
example-bom
模块pom.xml文件如下:
<parent>
<groupId>org.example</groupId>
<artifactId>maven-bom-examples</artifactId>
<version>${revision}</version>
</parent>
<!-- pom类型 -->
<packaging>pom</packaging>
<artifactId>example-bom</artifactId>
<properties>
<mysql.connector.java.version>8.0.33</mysql.connector.java.version>
<lingxi.cas.starter.version>1.1.4-RELEASE</lingxi.cas.starter.version>
<!-- 等等 -->
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.java.version}</version>
</dependency>
<dependency>
<groupId>com.qihoo.finance.lingxi</groupId>
<artifactId>lingxi-cas-starter</artifactId>
<version>${lingxi.cas.starter.version}</version>
</dependency>
<!-- 等等 -->
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<!-- 等等 -->
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Maven-dependencyManagement的使用
DepencyManagement应用场景
当我们的项目模块很多的时候,我们使用Maven管理项目非常方便,帮助我们管理构建、文档、报告、依赖、scms、发布、分发的方法。可以方便的编译代码、进行依赖管理、管理二进制库等等。
由于我们的模块很多,所以我们又抽象了一层。为了项目的正确运行,必须让所有的子项目使用依赖项的统一版本,必须确保应用的各个项目的依赖项和版本一致,才能保证测试的和发布的是相同的结果。
在我们项目顶层的POM文件中,我们会看到dependencyManagement元素。通过它元素来管理jar包的版本,让子项目中引用一个依赖而不用显示的列出版本号。Maven会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用在这个dependencyManagement元素中指定的版本号。
父POMdependencyManagement
统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,才能保证测试的和发布的是相同的成果。 因此,在顶层pom中定义共同的依赖关系。同时可以避免在每个使用的子项目中都声明一个版本号,这样想升级或者切换到另一个版本时,只需要在父类容器里更新,不需要任何一个子项目的修改; 如果某个子项目需要另外一个版本号时,只需要在dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号。
父POM中dependencies
相对于dependencyManagement,所有生命在dependencies里的依赖都会自动引入,并默认被所有的子项目继承。
dependencies与dependencyManagement搭配使用
- dependencies即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(全部继承)
- dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本
对于Maven约定优于配置的理解,一方面对于小型项目基本满足我们的需要基本不需要自己配置东西,使用Maven已经配置好的,快速上手,学习成本降低;另一方面,对于不满足我们需要的还可以自定义设置,体现了灵活性。配置大量减少了,随着项目变的越复杂,这种优势就越明显。
注意:父pom中dependencyManagement版本优先级高于传递依赖版本
例子:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencyManagement>
该工程beanutils将会传递依赖logging 1.1.1
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency>
此时该工程中logging的版本将是1.2,即父pom dependencyManagement中的版本
https://blog.51cto.com/lightgao/9585651